jcifs-0.5.1 from tgz
authorFelix Schumacher <p0354740@isib001.(none)>
Wed, 6 Aug 2008 13:57:02 +0000 (15:57 +0200)
committerFelix Schumacher <p0354740@isib001.(none)>
Wed, 6 Aug 2008 13:57:02 +0000 (15:57 +0200)
Mon Aug 27 00:29:02 EDT 2001

jcifs-0.5.1

Chris did some great testing at the CIFS Conference Interoperability
Lab and found three minor bugs. They are described in detail here:

http://lists.samba.org/pipermail/jcifs/2001-August/001428.html

These packages will now work with Java 1.1 as well as Java 2.

Sun Jul 29 04:01:18 EDT 2001

jcifs-0.5

This is the final release of the 0.5 series. It is the most stable and
complete product the jCIFS team has to offer. There are no known bugs. A bug
in the renameTo operation (would not always return false when it should have)
has been fixed, API documentation improvements have been made, and a
entry to the FAQ has been added.

Fri Jul 13 18:54:37 EDT 2001

jcifs-0.5b2

Thanks to Rob for realizing that attempting to read the same file from
different processes/threads yielded an "The file is being used by another
process" exception. We had the share flags and access masks wrong. A
Log.CRITICAL_EXCEPTIONS mask has been added for logging messages to the
console. If:

    Log.setMask( Log.CRITICAL_EXCEPTIONS );

is set, the "Access denied", "Bad password", and "The device is not
ready" sorts of exceptions will NOT be printed. The default is still
Log.EXCEPTIONS which encompasses both Log.CRITICAL_EXCEPTIONS and regular
Log.EXCEPTIONS so existing code will not be affected.

Thu Jun 28 21:04:15 EDT 2001

jcifs-0.5b

This is the beta release of jcifs-0.5. The 0.5 series has already been
through a stable release and there are no know bugs so we are confident
that it will perform well. New features since jcifs-0.4 include:

o SmbFile.list() Bug Fix - The jcifs-0.4 package had a serious bug that
  caused a TRANS2_FIND_FIRST2/NEXT2 endless loop. It has been properly
  fixed. This should be the first *complete* stable release.
o Share, Server, and Workroup Enumeration - jCIFS can now list the shares
  on a server, servers of a workgroup, and workgroups on a network.
o CallNamedPipe, TransactNamedPipe, and CreateFile Named Pipe API (Paul)
o Complete SMB Filesharing URL Scheme IETF Draft Support - The smb://
  URL scheme has been fully implemented. (Chris)
o Transactions and RAP API
o Transactions - Full multi-part Transaction requests(used by Transact
  Named Pipes)
o Daylight Savings Bug Fix - jCIFS was not properly correcting for
  daylight savings. (Urban)
o Full SmbComNTCreateAndX Support - We now look just like NT 4 instead
  of Winblows 95 :~)
o Unicode Alignment Bug Fix - Unicode alignment was generally not
  correct and caused many problems in early 0.5dev releases.
o SmbFile Method Behaviors - Fixed canRead() and re-thought and soul
  searched over the meaning of each of these methods and their behavior
  in the smb://, smb://name, and Named Pipe contexts. These methods
  should start to get pretty stable at this point.
o Clean, No Wait Exiting - Examples and other programs would wait 15
  seconds before exiting. This has been fixed by making the Transport
  thread setDaemon( true ). Same for the NameServiceClient Thread.
o Full Tuneable Batching
o NetBIOS Scope Fix
o New getServer, getShare, isWorkgroup Methods
o SmbShell and SmbCrawler Utilities

Thanks deserved for this release to Chris, Steve, Paul, The DJ, Urban,
James, Thierry, savaJe Technologies, and Josef.

FILES:

   jcifs-0.5b.tgz      jar and javadoc only for UNIX
   jcifs-0.5b.zip      jar and javadoc only for WINDOWS
   jcifs-0.5b.jar      jar file only

NOTE: The source code is included in the above packages. If
you would like to actually build jCIFS the ANT jar files are packaged
separately:

   ant.tgz             ant jar files
   ant.zip             ditto

Just unpack one of the above in the jcifs_0.5b directory, set JAVA_HOME in
build.{sh,bat} to bootstrap Ant, and run $ ./build.sh smb or > build smb.

IMPORTANT:

The jcifs.netbios.ns.nameserver has been changed to jcifs.netbios.wins
and the jcifs.util.Config class should now be referenced as
jcifs.Config. Programs written for jcifs-0.4 will not run without making
these two changes at least.

The jCIFS project uses the 'Ant' build tool available here:

    http://jakarta.apache.org/ant/

If you have *any* trouble please let us know on the mailing list by
sending mail to jcifs@samba.org or to myself at mballen@erols.com.

Enjoy,
Michael B. Allen <mballen@erols.com>

--8<--

                               JCIFS
           Common Internet File System Client in 100% Java
                      http://jcifs.samba.org

This is the JCIFS SMB client library written in Java. In short it
will enable Java applications to remotely access shared directories
on SMB file servers(i.e. a Microsoft Windows "share"). It is a fairly
religious implementation of the CIFS specification supporting Unicode,
batching, multiplexing, encrypted authentication, transactions, named
pipes, share/server/workgroup enumeration, and more. It is licensed
under LGPL which means commercial organizations can legitimately use it
with their propertietary code(you just can't modify the library itself
without reciprocation).

REQUIREMENTS:

Java 1.1 or above - http://java.sun.com/products/

INSTALLATION

Just add the jar file to you classpath as you would with any other
jar. More specifically:

UNIX:

1) Go to http://jcifs.samba.org and download jcifs-0.5b.tgz
2) Put it someplace reasonable and extract it with:

  $ gunzip jcifs-0.5b.tgz
  $ tar -xvf jcifs-0.5b.tar

3) Add the jar to your classpath. There are two ways to do this. One is to
explicitly set it on the command line when you run your application like:

  $ java -cp path/to/jcifs-0.4b.jar MyApplication

or perhaps export it in your .profile/.bash_profile like:

  CLASSPATH=$CLASSPATH:/home/miallen/path/to/jcifs-0.5b.jar
  export CLASSPATH

WINDOWS:

1) Go to http://jcifs.samba.org and download jcifs-0.5b.zip
2) Extract it with winzip and put the files someplace reasonable.
3) Add the jar to your classpath. There are two ways to do this. One is to
explicitly set it on the command line when you run your application like:

  C:\jcifs> java -cp jcifs-0.4b.jar MyApplication

The other way is to alter your system environment but I'm not confident
I can tell you accurately how to do that.

It is also common that the CLASSPATH be specified in a shell script or
batch file. See build.{sh,bat} as a hint.

RUNNING JCIFS:

In general the public API is extremely simple. The jcifs.smb.SmbFile,
jcifs.smb.SmbFileInputStream, and jcifs.smb.SmbFileOutputStream
classes are analogous to the java.io.File, java.io.FileInputStream,
and java.io.FileOutputStream classes so if you know how to use those it
should be quite obvious how to use JCIFS provided you set any necessary
properties(such as wins) and understand the smb:// URL syntax.

Here's an example to retrieve a file:

  import jcifs.smb.*;

  jcifs.Config.setProperty( "wins", "192.168.1.230" );
  SmbFileInputStream in = new SmbFileInputStream(
       "smb://username:password@host/c/My Documents/report.txt" );
  byte[] b = new byte[65535];
  int n;
  while(( n = in.read( b )) > 0 ) {
      System.out.write( b, 0, n );
  }

You can also write, rename, list contents of a directory, enumerate
shares, communicate with Win32 Named Pipe Servers, ...etc.

The protocol handler for java.net.URL is also in place which means you
retrieve files using the URL class as you would with other protocols. For
example:

  Class.forName( "jcifs.Config" ); //ensure protocol handler is loaded
  URL url = new URL( "smb://user:pass@host/share/dir/file.txt" );
  InputStream in = url.openStream();

This will also work with whatever else uses the URL class internally. For
example if you use RMI you can serve class files from an SMB share and
use the codebase property:

  -Djava.rmi.server.codebase=smb://mymachine/c/download/myapp.jar

To execute the Put example you might do:

$ java -cp examples:jcifs-0.4b.jar Put smb://usr:pass@host/share/file.zip
582K transfered

API documentation is included.

WHAT IS SMB AND CIFS?

Server Message Block (SMB) is an application layer networking protocol
for file and print sharing. It is the de-facto networking protocol for
Microsoft Windows platforms. The Common Internet File System (CIFS)
is the more generic name for all that encompasses the protocol and its
many layers. Collectively this is the networking protocol used when you
"Map Network Drive...", issue "net use * \\server\share" commands, use
smbclient on UNIX, smbfs on Linux, Sharity, OS2, server vendors such as
Network Appliance, EMC, and others.

WHY DO YOU NEED JCIFS?

This client is 100% Java and will work the same in a variety of
environments from Palm Pilots and applets to any UNIX that supports
Java. Naturally you can choose to run your applications on a platform
that supports mapping or mounting remote volumes into the local
filesystem but this assumes you know what shares you are accessing in
advance and what platform your application is running on(do you use
/mnt/pnt or H:\dir). Such an approach is not portable, unstable due to
unnecessary dependencies, and can be difficult to manage. JCIFS offers
Java applications that require access to SMB file services portability
and therefore the added stability that the UNIX environment can
provide. The JCIFS infrastructure is also highly extensible. If there
is a demand it will include a great deal of additional functionality
not available through a filesystem API such as printing, RPC, NT file
change notification, etc.

ACKNOWLEDGEMENTS

Special thanks to the Samba organization and Christopher R. Hertel for
starting the JCIFS project.

134 files changed:
README.txt [new file with mode: 0644]
build.bat [new file with mode: 0644]
build.sh [new file with mode: 0644]
build.xml [new file with mode: 0644]
examples/Append.java [new file with mode: 0644]
examples/CallNamedPipe.java [new file with mode: 0644]
examples/CifsTime.java [new file with mode: 0644]
examples/CreateFile.java [new file with mode: 0644]
examples/Delete.java [new file with mode: 0644]
examples/Exists.java [new file with mode: 0644]
examples/FileOps.java [new file with mode: 0644]
examples/Get.java [new file with mode: 0644]
examples/GetDate.java [new file with mode: 0644]
examples/GetURL.java [new file with mode: 0644]
examples/Interleave.java [new file with mode: 0644]
examples/List.java [new file with mode: 0644]
examples/LogTest.java [new file with mode: 0644]
examples/Mkdir.java [new file with mode: 0644]
examples/PipeTalk.java [new file with mode: 0644]
examples/Put.java [new file with mode: 0644]
examples/Query.java [new file with mode: 0644]
examples/RenameTo.java [new file with mode: 0644]
examples/SlowRead.java [new file with mode: 0644]
examples/SlowWrite.java [new file with mode: 0644]
examples/SmbCrawler.java [new file with mode: 0644]
examples/SmbShell.java [new file with mode: 0644]
examples/TestFile.java [new file with mode: 0644]
examples/TestSmbFile.java [new file with mode: 0644]
examples/ThreadedSmbCrawler.java [new file with mode: 0644]
examples/TortureTest3.java [new file with mode: 0644]
examples/TortureTest4.java [new file with mode: 0644]
examples/TortureTest5.java [new file with mode: 0644]
examples/TransactNamedPipe.java [new file with mode: 0644]
examples/jcifs.prp [new file with mode: 0644]
examples/pipes/callnp.c [new file with mode: 0644]
examples/pipes/callnp.exe [new file with mode: 0644]
examples/pipes/createf.c [new file with mode: 0644]
examples/pipes/createf.exe [new file with mode: 0644]
examples/pipes/createnp.c [new file with mode: 0644]
examples/pipes/createnp.exe [new file with mode: 0644]
examples/tt4.prp [new file with mode: 0644]
examples/zzz.java [new file with mode: 0644]
src/jcifs/Config.java [new file with mode: 0644]
src/jcifs/netbios/Lmhosts.java [new file with mode: 0644]
src/jcifs/netbios/Log.java [new file with mode: 0644]
src/jcifs/netbios/Name.java [new file with mode: 0644]
src/jcifs/netbios/NameQueryRequest.java [new file with mode: 0644]
src/jcifs/netbios/NameQueryResponse.java [new file with mode: 0644]
src/jcifs/netbios/NameServiceClient.java [new file with mode: 0644]
src/jcifs/netbios/NameServicePacket.java [new file with mode: 0644]
src/jcifs/netbios/NbtAddress.java [new file with mode: 0644]
src/jcifs/netbios/NbtException.java [new file with mode: 0644]
src/jcifs/netbios/NbtSocket.java [new file with mode: 0644]
src/jcifs/netbios/NodeStatusRequest.java [new file with mode: 0644]
src/jcifs/netbios/NodeStatusResponse.java [new file with mode: 0644]
src/jcifs/netbios/SessionRequestPacket.java [new file with mode: 0644]
src/jcifs/netbios/SessionRetargetResponsePacket.java [new file with mode: 0644]
src/jcifs/netbios/SessionServicePacket.java [new file with mode: 0644]
src/jcifs/netbios/SocketInputStream.java [new file with mode: 0644]
src/jcifs/netbios/SocketOutputStream.java [new file with mode: 0644]
src/jcifs/smb/AndXServerMessageBlock.java [new file with mode: 0644]
src/jcifs/smb/Handler.java [new file with mode: 0644]
src/jcifs/smb/Info.java [new file with mode: 0644]
src/jcifs/smb/Log.java [new file with mode: 0644]
src/jcifs/smb/NetServerEnum2.java [new file with mode: 0644]
src/jcifs/smb/NetServerEnum2Response.java [new file with mode: 0644]
src/jcifs/smb/NetShareEnum.java [new file with mode: 0644]
src/jcifs/smb/NetShareEnumResponse.java [new file with mode: 0644]
src/jcifs/smb/ServerMessageBlock.java [new file with mode: 0644]
src/jcifs/smb/SmbComBlankResponse.java [new file with mode: 0644]
src/jcifs/smb/SmbComCheckDirectory.jav [new file with mode: 0644]
src/jcifs/smb/SmbComClose.java [new file with mode: 0644]
src/jcifs/smb/SmbComCopy.jav [new file with mode: 0644]
src/jcifs/smb/SmbComCopyResponse.jav [new file with mode: 0644]
src/jcifs/smb/SmbComCreateDirectory.java [new file with mode: 0644]
src/jcifs/smb/SmbComDelete.java [new file with mode: 0644]
src/jcifs/smb/SmbComDeleteDirectory.java [new file with mode: 0644]
src/jcifs/smb/SmbComEcho.jav [new file with mode: 0644]
src/jcifs/smb/SmbComEchoResponse.jav [new file with mode: 0644]
src/jcifs/smb/SmbComFindClose2.java [new file with mode: 0644]
src/jcifs/smb/SmbComLogoffAndX.java [new file with mode: 0644]
src/jcifs/smb/SmbComMove.jav [new file with mode: 0644]
src/jcifs/smb/SmbComMoveResponse.jav [new file with mode: 0644]
src/jcifs/smb/SmbComNTCreateAndX.java [new file with mode: 0644]
src/jcifs/smb/SmbComNTCreateAndXResponse.java [new file with mode: 0644]
src/jcifs/smb/SmbComNegotiate.java [new file with mode: 0644]
src/jcifs/smb/SmbComNegotiateResponse.java [new file with mode: 0644]
src/jcifs/smb/SmbComOpenAndX.java [new file with mode: 0644]
src/jcifs/smb/SmbComOpenAndXResponse.java [new file with mode: 0644]
src/jcifs/smb/SmbComQueryInformation.java [new file with mode: 0644]
src/jcifs/smb/SmbComQueryInformationResponse.java [new file with mode: 0644]
src/jcifs/smb/SmbComReadAndX.java [new file with mode: 0644]
src/jcifs/smb/SmbComReadAndXResponse.java [new file with mode: 0644]
src/jcifs/smb/SmbComRename.java [new file with mode: 0644]
src/jcifs/smb/SmbComSessionSetupAndX.java [new file with mode: 0644]
src/jcifs/smb/SmbComSessionSetupAndXResponse.java [new file with mode: 0644]
src/jcifs/smb/SmbComTransaction.java [new file with mode: 0644]
src/jcifs/smb/SmbComTransactionResponse.java [new file with mode: 0644]
src/jcifs/smb/SmbComTreeConnectAndX.java [new file with mode: 0644]
src/jcifs/smb/SmbComTreeConnectAndXResponse.java [new file with mode: 0644]
src/jcifs/smb/SmbComTreeDisconnect.java [new file with mode: 0644]
src/jcifs/smb/SmbComWriteAndX.java [new file with mode: 0644]
src/jcifs/smb/SmbComWriteAndXResponse.java [new file with mode: 0644]
src/jcifs/smb/SmbException.java [new file with mode: 0644]
src/jcifs/smb/SmbFile.java [new file with mode: 0644]
src/jcifs/smb/SmbFileInputStream.java [new file with mode: 0644]
src/jcifs/smb/SmbFileOutputStream.java [new file with mode: 0644]
src/jcifs/smb/SmbNamedPipe.java [new file with mode: 0644]
src/jcifs/smb/SmbSession.java [new file with mode: 0644]
src/jcifs/smb/SmbTransport.java [new file with mode: 0644]
src/jcifs/smb/SmbTree.java [new file with mode: 0644]
src/jcifs/smb/SmbURL.java [new file with mode: 0644]
src/jcifs/smb/SmbURLConnection.java [new file with mode: 0644]
src/jcifs/smb/Trans2FindFirst2.java [new file with mode: 0644]
src/jcifs/smb/Trans2FindFirst2Response.java [new file with mode: 0644]
src/jcifs/smb/Trans2FindNext2.java [new file with mode: 0644]
src/jcifs/smb/Trans2QueryFSInformation.jav [new file with mode: 0644]
src/jcifs/smb/Trans2QueryFSInformationResponse.jav [new file with mode: 0644]
src/jcifs/smb/Trans2QueryPathInformation.java [new file with mode: 0644]
src/jcifs/smb/Trans2QueryPathInformationResponse.java [new file with mode: 0644]
src/jcifs/smb/TransCallNamedPipe.java [new file with mode: 0644]
src/jcifs/smb/TransCallNamedPipeResponse.java [new file with mode: 0644]
src/jcifs/smb/TransTransactNamedPipe.java [new file with mode: 0644]
src/jcifs/smb/TransTransactNamedPipeResponse.java [new file with mode: 0644]
src/jcifs/smb/TransWaitNamedPipe.java [new file with mode: 0644]
src/jcifs/smb/TransWaitNamedPipeResponse.java [new file with mode: 0644]
src/jcifs/smb/TransactNamedPipeInputStream.java [new file with mode: 0644]
src/jcifs/smb/TransactNamedPipeOutputStream.java [new file with mode: 0644]
src/jcifs/util/Config.java [new file with mode: 0644]
src/jcifs/util/DES.java [new file with mode: 0644]
src/jcifs/util/Log.java [new file with mode: 0644]
src/jcifs/util/LogWriter.java [new file with mode: 0644]
src/jcifs/util/MD4.java [new file with mode: 0644]
src/jcifs/util/PropertiesTree.java [new file with mode: 0644]

diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..ea26918
--- /dev/null
@@ -0,0 +1,249 @@
+Mon Aug 27 00:29:02 EDT 2001
+
+jcifs-0.5.1
+
+Chris did some great testing at the CIFS Conference Interoperability
+Lab and found three minor bugs. They are described in detail here:
+
+http://lists.samba.org/pipermail/jcifs/2001-August/001428.html
+
+These packages will now work with Java 1.1 as well as Java 2.
+
+Sun Jul 29 04:01:18 EDT 2001
+
+jcifs-0.5
+
+This is the final release of the 0.5 series. It is the most stable and
+complete product the jCIFS team has to offer. There are no known bugs. A bug
+in the renameTo operation (would not always return false when it should have)
+has been fixed, API documentation improvements have been made, and a
+entry to the FAQ has been added.
+
+Fri Jul 13 18:54:37 EDT 2001
+
+jcifs-0.5b2
+
+Thanks to Rob for realizing that attempting to read the same file from
+different processes/threads yielded an "The file is being used by another
+process" exception. We had the share flags and access masks wrong. A
+Log.CRITICAL_EXCEPTIONS mask has been added for logging messages to the
+console. If:
+
+    Log.setMask( Log.CRITICAL_EXCEPTIONS );
+
+is set, the "Access denied", "Bad password", and "The device is not
+ready" sorts of exceptions will NOT be printed. The default is still
+Log.EXCEPTIONS which encompasses both Log.CRITICAL_EXCEPTIONS and regular
+Log.EXCEPTIONS so existing code will not be affected.
+
+Thu Jun 28 21:04:15 EDT 2001
+
+jcifs-0.5b
+
+This is the beta release of jcifs-0.5. The 0.5 series has already been
+through a stable release and there are no know bugs so we are confident
+that it will perform well. New features since jcifs-0.4 include:
+
+o SmbFile.list() Bug Fix - The jcifs-0.4 package had a serious bug that
+  caused a TRANS2_FIND_FIRST2/NEXT2 endless loop. It has been properly
+  fixed. This should be the first *complete* stable release.
+o Share, Server, and Workroup Enumeration - jCIFS can now list the shares
+  on a server, servers of a workgroup, and workgroups on a network.
+o CallNamedPipe, TransactNamedPipe, and CreateFile Named Pipe API (Paul)
+o Complete SMB Filesharing URL Scheme IETF Draft Support - The smb://
+  URL scheme has been fully implemented. (Chris)
+o Transactions and RAP API
+o Transactions - Full multi-part Transaction requests(used by Transact
+  Named Pipes)
+o Daylight Savings Bug Fix - jCIFS was not properly correcting for
+  daylight savings. (Urban)
+o Full SmbComNTCreateAndX Support - We now look just like NT 4 instead
+  of Winblows 95 :~)
+o Unicode Alignment Bug Fix - Unicode alignment was generally not
+  correct and caused many problems in early 0.5dev releases.
+o SmbFile Method Behaviors - Fixed canRead() and re-thought and soul
+  searched over the meaning of each of these methods and their behavior
+  in the smb://, smb://name, and Named Pipe contexts. These methods
+  should start to get pretty stable at this point.
+o Clean, No Wait Exiting - Examples and other programs would wait 15
+  seconds before exiting. This has been fixed by making the Transport
+  thread setDaemon( true ). Same for the NameServiceClient Thread.
+o Full Tuneable Batching
+o NetBIOS Scope Fix
+o New getServer, getShare, isWorkgroup Methods
+o SmbShell and SmbCrawler Utilities
+
+Thanks deserved for this release to Chris, Steve, Paul, The DJ, Urban,
+James, Thierry, savaJe Technologies, and Josef.
+
+FILES:
+
+   jcifs-0.5b.tgz      jar and javadoc only for UNIX
+   jcifs-0.5b.zip      jar and javadoc only for WINDOWS
+   jcifs-0.5b.jar      jar file only
+
+NOTE: The source code is included in the above packages. If
+you would like to actually build jCIFS the ANT jar files are packaged
+separately:
+
+   ant.tgz             ant jar files
+   ant.zip             ditto
+
+Just unpack one of the above in the jcifs_0.5b directory, set JAVA_HOME in
+build.{sh,bat} to bootstrap Ant, and run $ ./build.sh smb or > build smb.
+
+IMPORTANT:
+
+The jcifs.netbios.ns.nameserver has been changed to jcifs.netbios.wins
+and the jcifs.util.Config class should now be referenced as
+jcifs.Config. Programs written for jcifs-0.4 will not run without making
+these two changes at least.
+
+The jCIFS project uses the 'Ant' build tool available here:
+
+    http://jakarta.apache.org/ant/
+
+If you have *any* trouble please let us know on the mailing list by
+sending mail to jcifs@samba.org or to myself at mballen@erols.com.
+
+Enjoy,
+Michael B. Allen <mballen@erols.com>
+
+--8<--
+
+                               JCIFS
+           Common Internet File System Client in 100% Java
+                      http://jcifs.samba.org
+
+
+This is the JCIFS SMB client library written in Java. In short it
+will enable Java applications to remotely access shared directories
+on SMB file servers(i.e. a Microsoft Windows "share"). It is a fairly
+religious implementation of the CIFS specification supporting Unicode,
+batching, multiplexing, encrypted authentication, transactions, named
+pipes, share/server/workgroup enumeration, and more. It is licensed
+under LGPL which means commercial organizations can legitimately use it
+with their propertietary code(you just can't modify the library itself
+without reciprocation).
+
+REQUIREMENTS:
+
+Java 1.1 or above - http://java.sun.com/products/
+
+INSTALLATION
+
+Just add the jar file to you classpath as you would with any other
+jar. More specifically:
+
+UNIX:
+
+1) Go to http://jcifs.samba.org and download jcifs-0.5b.tgz
+2) Put it someplace reasonable and extract it with:
+
+  $ gunzip jcifs-0.5b.tgz
+  $ tar -xvf jcifs-0.5b.tar
+
+3) Add the jar to your classpath. There are two ways to do this. One is to
+explicitly set it on the command line when you run your application like:
+
+  $ java -cp path/to/jcifs-0.4b.jar MyApplication
+
+or perhaps export it in your .profile/.bash_profile like:
+
+  CLASSPATH=$CLASSPATH:/home/miallen/path/to/jcifs-0.5b.jar
+  export CLASSPATH
+
+WINDOWS:
+
+1) Go to http://jcifs.samba.org and download jcifs-0.5b.zip
+2) Extract it with winzip and put the files someplace reasonable.
+3) Add the jar to your classpath. There are two ways to do this. One is to
+explicitly set it on the command line when you run your application like:
+
+  C:\jcifs> java -cp jcifs-0.4b.jar MyApplication
+
+The other way is to alter your system environment but I'm not confident
+I can tell you accurately how to do that.
+
+It is also common that the CLASSPATH be specified in a shell script or
+batch file. See build.{sh,bat} as a hint.
+
+RUNNING JCIFS:
+
+In general the public API is extremely simple. The jcifs.smb.SmbFile,
+jcifs.smb.SmbFileInputStream, and jcifs.smb.SmbFileOutputStream
+classes are analogous to the java.io.File, java.io.FileInputStream,
+and java.io.FileOutputStream classes so if you know how to use those it
+should be quite obvious how to use JCIFS provided you set any necessary
+properties(such as wins) and understand the smb:// URL syntax.
+
+Here's an example to retrieve a file:
+
+  import jcifs.smb.*;
+
+  jcifs.Config.setProperty( "wins", "192.168.1.230" );
+  SmbFileInputStream in = new SmbFileInputStream(
+       "smb://username:password@host/c/My Documents/report.txt" );
+  byte[] b = new byte[65535];
+  int n;
+  while(( n = in.read( b )) > 0 ) {
+      System.out.write( b, 0, n );
+  }
+
+You can also write, rename, list contents of a directory, enumerate
+shares, communicate with Win32 Named Pipe Servers, ...etc.
+
+The protocol handler for java.net.URL is also in place which means you
+retrieve files using the URL class as you would with other protocols. For
+example:
+
+  Class.forName( "jcifs.Config" ); //ensure protocol handler is loaded
+  URL url = new URL( "smb://user:pass@host/share/dir/file.txt" );
+  InputStream in = url.openStream();
+
+This will also work with whatever else uses the URL class internally. For
+example if you use RMI you can serve class files from an SMB share and
+use the codebase property:
+
+  -Djava.rmi.server.codebase=smb://mymachine/c/download/myapp.jar
+
+To execute the Put example you might do:
+
+$ java -cp examples:jcifs-0.4b.jar Put smb://usr:pass@host/share/file.zip
+##########
+582K transfered
+
+API documentation is included.
+
+WHAT IS SMB AND CIFS?
+
+Server Message Block (SMB) is an application layer networking protocol
+for file and print sharing. It is the de-facto networking protocol for
+Microsoft Windows platforms. The Common Internet File System (CIFS)
+is the more generic name for all that encompasses the protocol and its
+many layers. Collectively this is the networking protocol used when you
+"Map Network Drive...", issue "net use * \\server\share" commands, use
+smbclient on UNIX, smbfs on Linux, Sharity, OS2, server vendors such as
+Network Appliance, EMC, and others.
+
+WHY DO YOU NEED JCIFS?
+
+This client is 100% Java and will work the same in a variety of
+environments from Palm Pilots and applets to any UNIX that supports
+Java. Naturally you can choose to run your applications on a platform
+that supports mapping or mounting remote volumes into the local
+filesystem but this assumes you know what shares you are accessing in
+advance and what platform your application is running on(do you use
+/mnt/pnt or H:\dir). Such an approach is not portable, unstable due to
+unnecessary dependencies, and can be difficult to manage. JCIFS offers
+Java applications that require access to SMB file services portability
+and therefore the added stability that the UNIX environment can
+provide. The JCIFS infrastructure is also highly extensible. If there
+is a demand it will include a great deal of additional functionality
+not available through a filesystem API such as printing, RPC, NT file
+change notification, etc.
+
+ACKNOWLEDGEMENTS
+
+Special thanks to the Samba organization and Christopher R. Hertel for
+starting the JCIFS project.
diff --git a/build.bat b/build.bat
new file mode 100644 (file)
index 0000000..90a8966
--- /dev/null
+++ b/build.bat
@@ -0,0 +1,10 @@
+@echo off
+
+REM set JAVA_HOME=C:\Program Files\JavaSoft\JRE\1.2
+set JAVA_HOME=C:\jdk1.2.2
+
+set JAVA=%JAVA_HOME%\bin\java
+set CLASSPATH=ant\ant.jar;ant\jaxp.jar;ant\parser.jar
+
+"%JAVA%" -classpath "%CLASSPATH%" -Dant.home=ant org.apache.tools.ant.Main %1 %2 %3 %4 %5 %6 %7 %8 %9 -buildfile build.xml
+
diff --git a/build.sh b/build.sh
new file mode 100644 (file)
index 0000000..556c1f6
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+JAVA_HOME=/usr/local/java
+CLASSPATH=ant/ant.jar:ant/jaxp.jar:ant/parser.jar:${JAVA_HOME}/lib/tools.jar
+
+$JAVA_HOME/bin/java -classpath $CLASSPATH org.apache.tools.ant.Main -buildfile build.xml $@
diff --git a/build.xml b/build.xml
new file mode 100644 (file)
index 0000000..038b4f6
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<!--
+
+       This is an "Ant" build file. See http://jakarta.apache.org/ant/index.html for details.
+
+--> 
+<project name="jcifs" default="main" basedir=".">
+       <target name="main">
+               <echo message="    TARGETS:"/>
+               <echo message="        smb &lt;-- to build jcifs"/>
+               <echo message="        netbios"/>
+               <echo message="        util"/>
+               <echo message="        clean"/>
+               <echo message="        jar"/>
+               <echo message="        tgz"/>
+               <echo message="        zip"/>
+               <echo message="        javadoc"/>
+       </target>
+
+       <target name="util">
+               <mkdir dir="build"/>
+               <javac srcdir="src"
+                               destdir="build"
+                               includes="jcifs/util/*.java"
+                               debug="on"/>
+               <javac srcdir="src"
+                               destdir="build"
+                               includes="jcifs/Config.java"
+                               debug="on"/>
+       </target>
+       <target name="netbios" depends="util">
+               <mkdir dir="build"/>
+               <javac srcdir="src"
+                               destdir="build"
+                               includes="jcifs/netbios/*.java"
+                               debug="on"/>
+       </target>
+       <target name="smb" depends="netbios,util">
+               <mkdir dir="build"/>
+               <javac srcdir="src"
+                               destdir="build"
+                               includes="jcifs/smb/*.java"
+                               debug="on"/>
+       </target>
+
+       <target name="clean">
+               <delete dir="build"/>
+       </target>
+       <target name="jar" depends="smb">
+               <jar jarfile="jcifs-0.5.1.jar" basedir="build"/>
+       </target>
+
+       <target name="tgz">
+               <copy todir="dist_tmp/jcifs_0.5.1">
+                       <fileset dir="." excludes="ant,**/.*,build,jcifs.prp,**/*.tgz,**/*.zip"/>
+               </copy>
+               <tar tarfile="jcifs-0.5.1.tar" basedir="dist_tmp"/>
+               <gzip src="jcifs-0.5.1.tar" zipfile="jcifs-0.5.1.tgz"/>
+               <delete file="jcifs-0.5.1.tar"/>
+               <delete dir="dist_tmp"/>
+       </target>
+       <target name="zip">
+               <copy todir="dist_tmp/jcifs_0.5.1">
+                       <fileset dir="." excludes="ant,**/.*,build,jcifs.prp,**/*.tgz,**/*.zip"/>
+               </copy>
+               <fixcrlf srcdir="dist_tmp" cr="add" tab="remove" tablength="4" excludes="**/*.jar,**/*.exe"/>
+               <zip zipfile="jcifs-0.5.1.zip" basedir="dist_tmp"/>
+               <delete dir="dist_tmp"/>
+       </target>
+
+       <target name="javadoc">
+               <delete dir="docs/api"/>
+               <mkdir dir="docs/api"/>
+               <javadoc sourcefiles="jcifs/netbios/NbtAddress,jcifs/smb/SmbFile,jcifs/smb/SmbNamedPipe,jcifs/smb/SmbFileInputStream,jcifs/smb/SmbFileOutputStream,jcifs/smb/SmbURLConnection,jcifs/util/Config,jcifs/util/PropertiesTree,jcifs/util/Log"
+                               sourcepath="src"
+                               destdir="docs/api"
+                               overview="docs/overview.html"
+                               author="true"
+                               version="true"
+                               use="true"
+                               windowtitle="jcifs API">
+                       <!--link href="http://java.sun.com/products/jdk/1.2/docs/api/"/-->
+               </javadoc>
+       </target>
+</project>
diff --git a/examples/Append.java b/examples/Append.java
new file mode 100644 (file)
index 0000000..a685320
--- /dev/null
@@ -0,0 +1,39 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFile;
+import jcifs.smb.SmbFileOutputStream;
+
+public class Append {
+
+       public static void main( String argv[] ) throws Exception {
+
+               SmbFile f = new SmbFile( argv[0] );
+               SmbFileOutputStream out = new SmbFileOutputStream( f, true );
+
+               byte[] msg;
+               int i = 0;
+               while( i++ < 10 ) {
+                       msg = new String( "this is msg #" + i ).getBytes();
+                       out.write( msg );
+                       Thread.sleep( 17000 );
+               }
+
+               out.close();
+       }
+}
diff --git a/examples/CallNamedPipe.java b/examples/CallNamedPipe.java
new file mode 100644 (file)
index 0000000..a8e584d
--- /dev/null
@@ -0,0 +1,53 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbNamedPipe;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
+public class CallNamedPipe {
+
+       public static void main( String[] argv ) throws Exception {
+
+               if( argv.length < 2 ) {
+                       throw new IllegalArgumentException( "args: <smburl> <filedatatosend> <filetowriterecvdata>" );
+               }
+
+               byte[] b = new byte[65535];
+               FileInputStream fin = new FileInputStream( argv[1] );
+               FileOutputStream fos = new FileOutputStream( argv[2] );
+
+               SmbNamedPipe pipe = new SmbNamedPipe( argv[0],
+                               SmbNamedPipe.PIPE_TYPE_RDWR | SmbNamedPipe.PIPE_TYPE_CALL );
+               OutputStream out = pipe.getNamedPipeOutputStream();
+               InputStream in = pipe.getNamedPipeInputStream();
+
+               int n = fin.read( b );
+               System.out.println( "writing " + n + " bytes" );
+               out.write( b, 0, n );
+               n = in.read(b);
+               System.out.println( "read " + n + " bytes" );
+               fos.write(b, 0, n );
+
+               fin.close();
+               fos.close();
+               out.close();
+       }
+}
diff --git a/examples/CifsTime.java b/examples/CifsTime.java
new file mode 100644 (file)
index 0000000..7869752
--- /dev/null
@@ -0,0 +1,65 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import java.util.Date;
+import java.util.TimeZone;
+
+public class CifsTime {
+
+       // Observed dates reporting ServerTimeZone=240
+       // file last modified date = { low, high };
+
+       // Mon Mar 26 23:14:42 EST 2001 (no DST)
+       static final int[] D = { 0x10BE3D00, 0x01C0B66C };
+
+       // Mon Apr 30 03:17:14 EST 2001 (in DST)
+       //static final int[] D = { 0x9474B900, 0x01C0D145 };
+
+       static final long MILLISECONDS_BETWEEN_1970_AND_1601 = 11644473600000L;
+
+       static long calcDate() {
+               int lo, hi;
+               long t;
+
+               t = ((long)D[1] << 32 ) | ( (long)D[0] & 0xFFFFFFFFL );
+               t = ( t / 10000L - MILLISECONDS_BETWEEN_1970_AND_1601 );
+
+               if( TimeZone.getDefault().inDaylightTime( new Date() )) {
+                       // in dst
+
+                       if( TimeZone.getDefault().inDaylightTime( new Date( t ))) {
+                               // t was also generated in dst too so no correction
+                               return t;
+                       }
+                       // t was not generated during dst so add 1 hour
+                       return t + 3600000L;
+               } else {
+                       // not in dst
+
+                       if( TimeZone.getDefault().inDaylightTime( new Date( t ))) {
+                               // t was generated in dst so subtract 1 hour
+                               return t - 3600000L;
+                       }
+                       // t was also not generated in dst so no correction
+                       return t;
+               }
+       }
+       public static void main( String[] argv ) throws Exception {
+               System.out.println( new Date( calcDate() ));
+       }
+}
diff --git a/examples/CreateFile.java b/examples/CreateFile.java
new file mode 100644 (file)
index 0000000..1dfc624
--- /dev/null
@@ -0,0 +1,29 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFileOutputStream;
+
+public class CreateFile {
+
+       public static void main( String argv[] ) throws Exception {
+
+               SmbFileOutputStream out = new SmbFileOutputStream( argv[0], true );
+               out.close();
+       }
+}
+
diff --git a/examples/Delete.java b/examples/Delete.java
new file mode 100644 (file)
index 0000000..be09979
--- /dev/null
@@ -0,0 +1,35 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFile;
+
+public class Delete {
+
+       public static void main( String argv[] ) throws Exception {
+
+               long t0 = System.currentTimeMillis();
+
+               SmbFile f = new SmbFile( argv[0] );
+               if( f.delete() ) {
+                       System.out.println( f.getCanonicalPath() + " deleted " + ( System.currentTimeMillis() - t0 ) + "ms" );
+               } else {
+                       System.out.println( f.getCanonicalPath() + " deleted failed" );
+               }
+       }
+}
+
diff --git a/examples/Exists.java b/examples/Exists.java
new file mode 100644 (file)
index 0000000..d6ddf61
--- /dev/null
@@ -0,0 +1,33 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFile;
+
+public class Exists {
+
+       public static void main( String argv[] ) throws Exception {
+
+               SmbFile f = new SmbFile( argv[0] );
+               if( f.exists() ) {
+                       System.out.println( argv[0] + " exists" );
+               } else {
+                       System.out.println( argv[0] + " does not exist" );
+               }
+       }
+}
+
diff --git a/examples/FileOps.java b/examples/FileOps.java
new file mode 100644 (file)
index 0000000..2b717ee
--- /dev/null
@@ -0,0 +1,289 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+/* Test the following file operations:
+ * 
+ * canRead
+ *     false - a target that is already open by another process
+ *     false - the target does not exist
+ *     true  - the file exists and there are no sharing issues
+ * canWrite
+ *     true  - the file exists and there are no sharing issues
+ *     false - the file is marked read-only
+ *     false - the file does not exist
+ * delete
+ *     true  - the file existed and was succcessfully deleted
+ *     false - the target did not exist
+ *     false - the target is a share, server, workgroup or similar
+ *     false - the target or file under the target directory failed was read-only
+ * exists
+ *     true  - the target, share, IPC share, named pipe, server, or workgroup exists
+ *     false - the opposite of the above
+ * isDirectory
+ *     true  - the target is a workgroup, server, share, or directory
+ *     false - the target is not one of the above
+ * isFile
+ *     direct opposite of isDirectory
+ * isHidden
+ *     true  - target is share ending in $ or marked as hidden
+ * length
+ *     the file was created to be no larger than ~2G and reports back the size specified
+ * mkdir
+ *     true  - a directory was created successfully
+ *     false - the directory could not be created
+ * renameTo
+ *     true  - the target was renamed
+ */
+
+import jcifs.smb.*;
+import java.io.IOException;
+
+public class FileOps {
+
+       public static void main( String argv[] ) throws Exception {
+
+               if( argv.length != 1 ) {
+                       System.out.println( "Must provide an SMB URL of a remote location on which tests will be conducted." );
+                       System.exit( 1 );
+               }
+
+               SmbFile s = new SmbFile( argv[0] );
+               SmbFile d = new SmbFile( s, "JcifsTestOpsDir" );
+
+       // delete - Delete the directory if it exists
+
+               if( d.delete() ) {
+                       System.out.println( "okay - delete " + d + " successfull" );
+               } else {
+                       System.out.println( "okay - delete " + d + " failed" );
+               }
+
+       // exists - Test the directory that should not exist
+
+               if( d.exists() ) {
+                       System.out.println( "fail - " + d + " still exists" );
+                       System.exit( 1 );
+               } else {
+                       System.out.println( "okay - " + d + " does not exist" );
+               }
+
+       // mkdir - Create the directory
+
+               if( d.mkdir() ) {
+                       System.out.println( "okay - mkdir " + d + " successfull" );
+               } else {
+                       System.out.println( "fail - mkdir " + d + " failed" );
+                       System.exit( 1 );
+               }
+
+       // exist - Test the directory with should exist now
+
+               if( d.exists() ) {
+                       System.out.println( "okay - " + d + " exists" );
+               } else {
+                       System.out.println( "fail - " + d + " was not successfully created" );
+                       System.exit( 1 );
+               }
+
+       // mkdir - Try to create a directory even though it already exists
+
+               if( d.mkdir() ) {
+                       System.out.println( "fail - mkdir " + d + " successfull" );
+                       System.exit( 1 );
+               } else {
+                       System.out.println( "okay - mkdir " + d + " failed" );
+               }
+
+       // Create a file to test against
+
+       SmbFile f = null;
+       try {
+               f = new SmbFile( d, "foo.txt" );
+               SmbFileOutputStream o = new SmbFileOutputStream( f );
+               o.write( "The Common Internet File System (CIFS) is the de-facto file sharing protocol on the Microsoft Windows platform. It is the underlying networking protocol used when accessing shares with Windows Explorer, the Network Neighborhood, via a Map Network Drive...  dialog, the C:\\> net use * \\\\server\\share commands, or smbclient on UNIX, smbfs on Linux, and elsewhere.\r\n".getBytes() );
+               o.close();
+       } catch( IOException ioe ) {
+               System.out.println( "fail - could not create file " + d + "/aboutcifs.txt");
+       }
+       System.out.println( "okay - created file " + d + "/aboutcifs.txt" );
+
+       // canRead - Test to see if the new file can be read
+
+               if( f.canRead() ) {
+                       System.out.println( "okay - canRead " + f + " successfull" );
+               } else {
+                       System.out.println( "fail - canRead " + f + " failed" );
+                       System.exit( 1 );
+               }
+
+       // canWrite - Test the file for writing
+
+               if( f.canWrite() ) {
+                       System.out.println( "okay - canWrite " + f + " successfull" );
+               } else {
+                       System.out.println( "fail - canWrite " + f + " failed" );
+                       System.exit( 1 );
+               }
+
+       // ASK USER TO FLIP ON READ-ONLY
+
+               System.out.println( "Please change the file " + f + " to read-only (hit return to continue)" );
+               System.in.read();
+
+       // canWrite - Test the file for writing
+
+               if( f.canWrite() ) {
+                       System.out.println( "fail - canWrite " + f + " returned true but it should have been marked read-only ... continuing on" );
+               } else {
+                       System.out.println( "okay - canWrite " + f + " failed" );
+               }
+
+       // Try to open the file for writing
+
+               try {
+                       SmbFileOutputStream w = new SmbFileOutputStream( f );
+                       w.close();
+                       System.out.println( "fail - successfully opened " + f + " for writing even though it should be marked read-only ... continuing on" );
+               } catch( IOException ioe ) {
+                       System.out.println( "okay - correctly failed to open " + f + " for writing" );
+               }
+
+       // renameTo - rename the file to bar.txt
+
+               SmbFile b = new SmbFile( d, "bar.txt" );
+
+               if( f.renameTo(b) ) {
+                       System.out.println( "okay - renameTo " + f + " to " + b + " successfull even with read-only" );
+                       if( b.renameTo(f) == false ) {
+                               System.out.println( "fail - but failed to rename file back to original!" );
+                               System.exit( 1 );
+                       }
+               } else {
+                       System.out.println( "fail - renameTo " + f + " should have been successfull even though the file is marked read-only" );
+               }
+
+       // ASK USER TO FLIP ON HIDDEN FLAG
+
+               System.out.println( "Please turn on the hidden attribute for " + f + " (hit return to continue)" );
+               System.in.read();
+
+       // isHidden - Test to see if the file is hidden
+
+               if( f.isHidden() ) {
+                       System.out.println( "okay - isHidden " + f + " is hidden" );
+               } else {
+                       System.out.println( "fail - isHidden " + f + " is not hidden but it should be ... continuing on" );
+               }
+
+       // canRead - Test canRead again with both hidden and read-only on
+
+               if( f.canRead() ) {
+                       System.out.println( "okay - canRead " + f + " was successfull with read-only and hidden both on" );
+               } else {
+                       System.out.println( "fail - canRead " + f + " failed with read-only and hidden both on" );
+               }
+
+       // canWrite - Test the file for writing again with read-only and hidden
+
+               if( f.canWrite() ) {
+                       System.out.println( "fail - canWrite " + f + " was successfull even though read-only is set ... continuing on" );
+               } else {
+                       System.out.println( "okay - canWrite " + f + " failed as it should being that read-only is set" );
+               }
+
+       // isDirectory - Test file as a directory
+
+               if( f.isDirectory() ) {
+                       System.out.println( "fail - isDirectory " + f + " returned true but it is NOT a directory" );
+               } else {
+                       System.out.println( "okay - isDirectory " + f + " is not a directory" );
+               }
+
+       // isDirectory - Test directory as a directory
+
+               if( d.isDirectory() ) {
+                       System.out.println( "okay - isDirectory " + d + " is a directory" );
+               } else {
+                       System.out.println( "fail - isDirectory " + d + " returned false but it really is a directory" );
+               }
+
+       // isFile - Test file as a file
+
+               if( f.isFile() ) {
+                       System.out.println( "okay - isFile " + f + " is a file" );
+               } else {
+                       System.out.println( "fail - isFile " + f + " return false but it is NOT a file" );
+               }
+
+       // isFile - Test directory as a file
+
+               if( d.isFile() ) {
+                       System.out.println( "fail - isFile " + d + " returned true but it is NOT a file" );
+               } else {
+                       System.out.println( "okay - isFile " + d + " is not a file" );
+               }
+
+       // delete - See if we can delete the file even though it's read-only
+
+               if( f.delete() ) {
+                       System.out.println( "fail - delete " + f + " should not have been successfull because it is read-only" );
+               } else {
+                       System.out.println( "okay - delete " + f + " failed because it is read-only" );
+               }
+
+       // Flip off both read-only and hidden
+
+               System.out.println( "Flipp off both read-only and hidden flags for " + f + " (hit return to continue)" );
+               System.in.read();
+
+       // length - Check to ensure that the length of the file is correct
+
+               if( f.length() == 363 ) {
+                       System.out.println( "okay - length " + f + " is correct" );
+               } else {
+                       System.out.println( "fail - length " + f + " is wrong: " + f.length() );
+               }
+
+               SmbFile r = new SmbFile( d.getParent(), "JcifsDeleteMe" );
+
+       // Must delete any left over directory from a previous run
+
+               if( r.delete() ) {
+                       System.out.println( "okay - delete " + r + " successfull" );
+               } else {
+                       System.out.println( "okay - delete " + r + " probably wasn't there" );
+               }
+
+       // renameTo - Rename the whole directory to JcifsDeleteMe
+
+               if( d.renameTo( r )) {
+                       System.out.println( "okay - renameTo " + d + " successfull even though it is a directory" );
+               } else {
+                       System.out.println( "fail - renameTo " + d + " failed" );
+               }
+
+       // delete - Now delete the whole workspace
+
+               if( r.delete() ) {
+                       System.out.println( "okay - delete " + d + " successfull" );
+               } else {
+                       System.out.println( "fail - delete " + d + " failed" );
+               }
+       }
+}
+
diff --git a/examples/Get.java b/examples/Get.java
new file mode 100644 (file)
index 0000000..0b18b30
--- /dev/null
@@ -0,0 +1,55 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFile;
+import jcifs.smb.SmbFileInputStream;
+import java.io.FileOutputStream;
+
+public class Get {
+
+       public static void main( String argv[] ) throws Exception {
+
+               SmbFile f = new SmbFile( argv[0] );
+               SmbFileInputStream in = new SmbFileInputStream( f );
+               FileOutputStream out = new FileOutputStream( f.getName() );
+
+               long t0 = System.currentTimeMillis();
+
+               byte[] b = new byte[65535];
+               int n, tot = 0;
+               long t1 = t0;
+               long t2;
+               while(( n = in.read( b )) > 0 ) {
+                       out.write( b, 0, n );
+                       tot += n;
+                       System.out.print( '#' );
+                       t2 = System.currentTimeMillis();
+                       System.out.print( t2 - t1 + "" );
+                       t1 = t2;
+               }
+
+               long t = System.currentTimeMillis() - t0;
+
+               System.out.println();
+               System.out.println( tot + " bytes transfered in " + ( t / 1000 ) + " seconds at " + (( tot / 1000 ) / Math.max( 1, ( t / 1000 ))) + "Kbytes/sec" );
+
+               in.close();
+               out.close();
+       }
+}
+
diff --git a/examples/GetDate.java b/examples/GetDate.java
new file mode 100644 (file)
index 0000000..9ccbc9b
--- /dev/null
@@ -0,0 +1,34 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import java.util.Date;
+import jcifs.smb.SmbFile;
+import java.text.SimpleDateFormat;
+import java.util.GregorianCalendar;
+
+public class GetDate {
+
+       public static void main( String argv[] ) throws Exception {
+               SmbFile f = new SmbFile( argv[0] );
+               Date d = new Date( f.lastModified() );
+               SimpleDateFormat sdf = new SimpleDateFormat( "EEEE, MMMM d, yyyy h:mm:ss a" );
+               sdf.setCalendar( new GregorianCalendar() );
+               System.out.println( sdf.format( d ));
+       }
+}
+
diff --git a/examples/GetURL.java b/examples/GetURL.java
new file mode 100644 (file)
index 0000000..1298554
--- /dev/null
@@ -0,0 +1,43 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import java.net.URL;
+import java.io.InputStream;
+
+public class GetURL {
+
+       public static void main( String argv[] ) throws Exception {
+
+               Class.forName( "jcifs.Config" );
+
+               URL url = new URL( argv[0] );
+               InputStream in = url.openStream();
+
+               if( in != null ) {
+                       byte[] buf = new byte[4096];
+                       int n;
+                       while(( n = in.read( buf )) != -1 ) {
+                               System.out.write( buf, 0, n );
+                       }
+               } else {
+                       System.out.println( "stream waz null" );
+               }
+               in.close();
+       }
+}
+
diff --git a/examples/Interleave.java b/examples/Interleave.java
new file mode 100644 (file)
index 0000000..3fc9fd9
--- /dev/null
@@ -0,0 +1,58 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.*;
+
+public class Interleave {
+
+       static class IThread extends Thread {
+               String url;
+
+               IThread( String url ) {
+                       this.url = url;
+               }
+
+               public void run() {
+                       try {
+                               yield();
+                               System.out.println( getName() + ": started" );
+                               SmbFileOutputStream o = new SmbFileOutputStream( url );
+                               o.close();
+                               System.out.println( getName() + ": done" );
+                       } catch( Exception x ) {
+                               x.printStackTrace();
+                       }
+               }
+       }
+
+       public static void main(String[] argv) throws Exception {
+               if( argv.length < 2 ) {
+                       System.out.println( "java Interleave dir numThreads" );
+                       return;
+               }
+       
+               int numThreads = Integer.parseInt( argv[1] );
+               IThread[] t = new IThread[numThreads];
+               for( int i = 0; i < numThreads; i++ ) {
+                       t[i] = new IThread( argv[0] + "/it" + i + ".tmp" );
+               }
+               for( int j = 0; j < numThreads; j++ ) {
+                       t[j].start();
+               }
+       }
+}
diff --git a/examples/List.java b/examples/List.java
new file mode 100644 (file)
index 0000000..33eb841
--- /dev/null
@@ -0,0 +1,43 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFile;
+import jcifs.util.Log;
+import java.util.Date;
+
+public class List {
+
+       public static void main( String[] argv ) throws Exception {
+
+               SmbFile file = new SmbFile( argv[0] );
+
+               long t1 = System.currentTimeMillis();
+               String[] files = file.list();
+               long t2 = System.currentTimeMillis() - t1;
+
+               if( files != null ) {
+                       for( int i = 0; i < files.length; i++ ) {
+                               System.out.print( " " + files[i] );
+                       }
+                       System.out.println();
+                       System.out.println( files.length + " files in " + t2 + "ms" );
+               } else {
+                       System.out.println( "no such file or directory" );
+               }
+       }
+}
diff --git a/examples/LogTest.java b/examples/LogTest.java
new file mode 100644 (file)
index 0000000..6fb3eac
--- /dev/null
@@ -0,0 +1,35 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.util.Log;
+
+public class LogTest {
+
+       public static void main( String[] argv ) {
+               Log.setMask(( Log.ALL | Log.EXCEPTIONS ) & ~Log.HEX_DUMPS );
+
+               Log.println( Log.WARNINGS, "LogTest warning", "you've been warned" );
+               Log.println( Log.DEBUGGING, "This is a debugging message", "MADE IT!" );
+               Log.printHexDump( "This will not be printed", "hello, world".getBytes() );
+               try {
+                       int i = 10/0;
+               } catch( Exception x ) {
+                       Log.printStackTrace( "LogTest exception", x );
+               }
+       }
+}
diff --git a/examples/Mkdir.java b/examples/Mkdir.java
new file mode 100644 (file)
index 0000000..b9e3f42
--- /dev/null
@@ -0,0 +1,34 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.util.Log;
+import jcifs.smb.SmbFile;
+
+public class Mkdir {
+
+       public static void main( String argv[] ) throws Exception {
+
+               SmbFile f = new SmbFile( argv[0] );
+               if( f.mkdir() ) {
+                       System.out.println( f.getCanonicalPath() + " created" );
+               } else {
+                       System.out.println( "mkdir failed: " + f.getCanonicalPath() );
+               }
+       }
+}
+
diff --git a/examples/PipeTalk.java b/examples/PipeTalk.java
new file mode 100644 (file)
index 0000000..0dc3408
--- /dev/null
@@ -0,0 +1,74 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbNamedPipe;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+public class PipeTalk {
+
+       static class ReceiverThread extends Thread {
+               InputStream in;
+               byte[] buf = new byte[20];
+               int n;
+
+               ReceiverThread( InputStream in ) {
+                       this.in = in;
+               }
+               public void run() {
+                       try {
+                               while(( n = in.read( buf )) != -1 ) {
+                                       System.out.println( new String( buf, 0, n ));
+                               }
+                       } catch( IOException ioe ) {
+                               ioe.printStackTrace();
+                       }
+               }
+       }
+
+       public static void main( String argv[] ) throws Exception {
+
+               SmbNamedPipe pipe = new SmbNamedPipe( argv[0], SmbNamedPipe.PIPE_TYPE_RDWR );
+               InputStream in = pipe.getNamedPipeInputStream();
+               OutputStream out = pipe.getNamedPipeOutputStream();
+
+               ReceiverThread rt = new ReceiverThread( in );
+               rt.start();
+
+               StringBuffer sb = new StringBuffer();
+               String msg;
+               int c;
+               while(( c = System.in.read() ) != -1 ) {
+                       if( c == '\n' ) {
+                               msg = sb.toString();
+                               if( msg.startsWith( "exi" )) {
+                                       break;
+                               }
+                               System.out.println( sb.toString() );
+                               out.write( msg.getBytes() );
+                               sb.setLength( 0 );
+                       } else {
+                               sb.append( (char)c );
+                       }
+               }
+               in.close();
+               out.close();
+       }
+}
+
diff --git a/examples/Put.java b/examples/Put.java
new file mode 100644 (file)
index 0000000..4317c4f
--- /dev/null
@@ -0,0 +1,49 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFile;
+import jcifs.smb.SmbFileOutputStream;
+import java.io.FileInputStream;
+
+public class Put {
+
+       public static void main( String argv[] ) throws Exception {
+
+               SmbFile f = new SmbFile( argv[0] );
+               FileInputStream in = new FileInputStream( f.getName() );
+               SmbFileOutputStream out = new SmbFileOutputStream( f );
+
+               long t0 = System.currentTimeMillis();
+
+               byte[] b = new byte[65535];
+               int n, tot = 0;
+               while(( n = in.read( b )) > 0 ) {
+                       out.write( b, 0, n );
+                       tot += n;
+                       System.out.print( '#' );
+               }
+
+               long t = System.currentTimeMillis() - t0;
+
+               System.out.println();
+               System.out.println( tot + " bytes transfered in " + ( t / 1000 ) + " seconds at " + (( tot / 1000 ) / Math.max( 1, ( t / 1000 ))) + "Kbytes/sec" );
+
+               in.close();
+               out.close();
+       }
+}
diff --git a/examples/Query.java b/examples/Query.java
new file mode 100644 (file)
index 0000000..17b7ac0
--- /dev/null
@@ -0,0 +1,26 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.netbios.NbtAddress;
+
+public class Query {
+
+       public static void main( String argv[] ) throws Exception {
+               System.out.println( NbtAddress.getByName( argv[0], 0x1b, "" ));
+       }
+}
diff --git a/examples/RenameTo.java b/examples/RenameTo.java
new file mode 100644 (file)
index 0000000..6d196c3
--- /dev/null
@@ -0,0 +1,34 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFile;
+
+public class RenameTo {
+
+       public static void main( String argv[] ) throws Exception {
+
+               SmbFile from = new SmbFile( argv[0] );
+               SmbFile to = new SmbFile( argv[1] );
+               if( from.renameTo( to )) {
+                       System.out.println( from.getCanonicalPath() + " renamed to " + to.getCanonicalPath() );
+               } else {
+                       System.out.println( "Failed to rename " + from.getCanonicalPath() + " to " + to.getCanonicalPath() );
+               }
+       }
+}
+
diff --git a/examples/SlowRead.java b/examples/SlowRead.java
new file mode 100644 (file)
index 0000000..7c297ce
--- /dev/null
@@ -0,0 +1,40 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFile;
+import jcifs.smb.SmbFileInputStream;
+import java.io.FileOutputStream;
+
+public class SlowRead {
+
+       public static void main( String argv[] ) throws Exception {
+
+               SmbFileInputStream in = new SmbFileInputStream( argv[0] );
+
+               byte[] b = new byte[10];
+               int n, tot = 0;
+               while(( n = in.read( b )) > 0 ) {
+                       System.out.write( b, 0, n );
+                       tot += n;
+                       Thread.sleep( 17000 );
+               }
+
+               in.close();
+       }
+}
+
diff --git a/examples/SlowWrite.java b/examples/SlowWrite.java
new file mode 100644 (file)
index 0000000..3d4c38a
--- /dev/null
@@ -0,0 +1,35 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFileOutputStream;
+
+public class SlowWrite {
+
+       public static void main( String argv[] ) throws Exception {
+
+               SmbFileOutputStream out = new SmbFileOutputStream( argv[0] );
+
+               for( int i = 0; i < 2; i++ ) {
+                       out.write( (new String( "hello" + i )).getBytes() );
+                       Thread.sleep( 17000 );
+               }
+
+               out.close();
+       }
+}
+
diff --git a/examples/SmbCrawler.java b/examples/SmbCrawler.java
new file mode 100644 (file)
index 0000000..3409868
--- /dev/null
@@ -0,0 +1,62 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFile;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.net.MalformedURLException;
+import java.io.IOException;
+
+public class SmbCrawler {
+
+       int maxDepth;
+
+       SmbCrawler( int maxDepth ) {
+               this.maxDepth = maxDepth;
+       }
+
+       void traverse( SmbFile f, int depth ) throws MalformedURLException, IOException {
+
+               if( depth == 0 ) {
+                       return;
+               }
+
+               String[] l = f.list();
+
+               for(int i = 0; l != null && i < l.length; i++ ) {
+                       try {
+                               SmbFile d = new SmbFile( f, l[i] );
+                               for( int j = maxDepth - depth; j > 0; j-- ) {
+                                       System.out.print( "    " );
+                               }
+                               System.out.println( l[i] );
+                               if( d.isDirectory() ) {
+                                       traverse( d, depth - 1 );
+                               }
+                       } catch( IOException ioe ) {
+                               System.out.println( l[i] + ": " + ioe.getMessage() );
+                       }
+               }
+       }
+
+       public static void main(String[] argv) throws Exception {
+               int depth = Integer.parseInt( argv[1] );
+               SmbCrawler sc = new SmbCrawler( depth );
+               sc.traverse( new SmbFile( argv[0] ), depth );
+       }
+}
diff --git a/examples/SmbShell.java b/examples/SmbShell.java
new file mode 100644 (file)
index 0000000..3793f0c
--- /dev/null
@@ -0,0 +1,110 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.*;
+import java.net.UnknownHostException;
+import java.net.MalformedURLException;
+
+public class SmbShell {
+
+    public static String readLine() throws Exception {
+        int c;
+        StringBuffer sb = new StringBuffer();
+        while(( c = System.in.read() ) != '\n' ) {
+            sb.append( (char)c );
+        }
+        return sb.toString().trim();
+    }
+
+    public static void main( String[] argv ) throws Exception {
+        int c;
+        String cmd, prompt;
+               SmbFile conn, tmp;
+
+               conn = new SmbFile( "smb://" );
+        while( true ) {
+                       try {
+                               if( conn.exists() ) {
+                                       prompt = new SmbFile( conn.getCanonicalPath() ).getName() + "> ";
+                               } else {
+                                       System.out.println( "error reading " + conn );
+                                       conn = new SmbFile( "smb://" );
+                                       continue;
+                               }
+                   System.out.print( prompt );
+       
+                   cmd = readLine();
+                   if( cmd.equals( "" ) ) {
+                   } else if( cmd.startsWith( "cd" )) {
+                       int i = cmd.indexOf( ' ' );
+                       String dir;
+                       if( i == -1 || (dir = cmd.substring( i ).trim()).length() == 0 ) {
+                                               conn = new SmbFile( "smb://" );
+                           continue;
+                       }
+                                       tmp = new SmbFile( conn.getCanonicalPath(), dir );
+                                       if( tmp.exists() ) {
+                                               if( tmp.isDirectory() ) {
+                                                       conn = tmp;
+                                               } else {
+                                                       System.out.println( dir + " is not a directory" );
+                                               }
+                                       } else {
+                                               System.out.println( "no such directory" );
+                                       }
+                   } else if( cmd.startsWith( "ls" )) {
+                       int i = cmd.indexOf( ' ' );
+                                       SmbFile d = conn;
+                       String dir;
+                       if( i != -1 && (dir = cmd.substring( i ).trim()).length() != 0 ) {
+                                               d = new SmbFile( conn, dir );
+                       }
+                                       String[] list = d.list();
+                                       if( list != null ) {
+                                               for( int j = 0; j < list.length; j++ ) {
+                                                       System.out.print( " " + list[j] );
+                                               }
+                                               System.out.println();
+                                               System.out.println( list.length + " items" );
+                                       } else {
+                                               System.out.println( "no such file or directory" );
+                                       }
+                   } else if( cmd.startsWith( "pwd" )) {
+                                       System.out.println( conn.getCanonicalPath() );
+                   } else if( cmd.startsWith( "q" ) ||
+                               cmd.startsWith( "x" ) ||
+                               cmd.startsWith( "ex" ) ||
+                               cmd.startsWith( "by" )) {
+                       break;
+                   } else {
+                       System.out.println( "commands:" );
+                       System.out.println( "  ls [dir|file]" );
+                       System.out.println( "  cd dir" );
+                       System.out.println( "  pwd" );
+                       System.out.println( "  quit" );
+                   }
+                       } catch( UnknownHostException uhe ) {
+                               uhe.printStackTrace();
+                       } catch( MalformedURLException mue ) {
+                               mue.printStackTrace();
+                               conn = null;
+                       }
+        }
+               System.exit( 0 );
+    }
+}
diff --git a/examples/TestFile.java b/examples/TestFile.java
new file mode 100644 (file)
index 0000000..97a644c
--- /dev/null
@@ -0,0 +1,34 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import java.io.File;
+
+public class TestFile {
+
+       public static void main( String argv[] ) throws Exception {
+               File f = new File( argv[0] );
+               System.out.println( "toString()=" + f.toString());
+               System.out.println( "getCanonicalPath()=" + f.getCanonicalPath());
+               System.out.println( "getName()=" + f.getName());
+               System.out.println( "getParent()=" + f.getParent());
+               System.out.println( "getPath()=" + f.getPath());
+               System.out.println( "toURL().toString()=" + f.toURL().toString());
+               System.out.println( "equals( " + argv[1] + " )=" + f.equals( new File( argv[1] )));
+       }
+}
+
diff --git a/examples/TestSmbFile.java b/examples/TestSmbFile.java
new file mode 100644 (file)
index 0000000..22eaa28
--- /dev/null
@@ -0,0 +1,44 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.*;
+
+public class TestSmbFile {
+
+       public static void main( String argv[] ) throws Exception {
+               SmbFile f;
+               if( argv.length == 1 ) {
+                       f = new SmbFile( argv[0] );
+               } else {
+                       f = new SmbFile( argv[0], argv[1] );
+               }
+               System.out.println( "toString()=" + f.toString());
+               System.out.println( "getCanonicalPath()=" + f.getCanonicalPath());
+               System.out.println( "getName()=" + f.getName());
+               System.out.println( "getParent()=" + f.getParent());
+               System.out.println( "getPath()=" + f.getPath());
+               System.out.println( "getServer()=" + f.getServer());
+               System.out.println( "getShare()=" + f.getShare());
+               System.out.println( "isWorkgroup()=" + f.isWorkgroup());
+               System.out.println( "toURL().toString()=" + f.toURL().toString());
+               if( argv.length > 2 ) {
+                       System.out.println( "equals( " + argv[1] + " )=" + f.equals( new SmbFile( argv[1] )));
+               }
+       }
+}
+
diff --git a/examples/ThreadedSmbCrawler.java b/examples/ThreadedSmbCrawler.java
new file mode 100644 (file)
index 0000000..ce775b2
--- /dev/null
@@ -0,0 +1,110 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbFile;
+import jcifs.util.Log;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.net.MalformedURLException;
+import java.io.IOException;
+
+public class ThreadedSmbCrawler {
+
+       class DirEntry {
+               SmbFile dir;
+               int depth;
+
+               DirEntry( SmbFile dir, int depth ) {
+                       this.dir = dir;
+                       this.depth = depth;
+               }
+       }
+
+       class SmbCrawlerThread extends Thread {
+
+               StringBuffer sb = new StringBuffer();
+
+               SmbCrawlerThread() {
+               }
+
+               public void run() {
+                       while( true ) {
+                               try {
+                                       DirEntry e;
+
+                                       synchronized( dirList ) {
+                                               while( dirList.isEmpty() ) {
+                                                       dirList.wait( 500 );
+                                               }
+                                               e = (DirEntry)dirList.remove( 0 );
+                                       }
+
+                                       if( e.depth == 0 ) {
+                                               continue;
+                                       }
+
+                                       String[] l = e.dir.list();
+
+                                       int n = maxDepth - e.depth;
+
+                                       for(int i = 0; l != null && i < l.length; i++ ) {
+                                               try {
+                                                       sb.setLength( 0 );
+                                                       for( int k = 0; k < n; k++ ) {
+                                                               sb.append( "    " );
+                                                       }
+                                                       SmbFile d = new SmbFile( e.dir, l[i] );
+                                                       System.out.println( sb.append( d ));
+                                                       if( d.isDirectory() ) {
+                                                               synchronized( dirList ) {
+                                                                       dirList.add( new DirEntry( d, e.depth - 1 ));
+                                                                       dirList.notify();
+                                                               }
+                                                       }
+                                               } catch( IOException ioe ) {
+                                                       ioe.printStackTrace();
+                                               }
+                                       }
+                               } catch( Exception x ) {
+                                       x.printStackTrace();
+                               }
+                       }
+               }
+       }
+
+       LinkedList dirList;
+       int maxDepth;
+
+       ThreadedSmbCrawler( String dir, int maxDepth, int numThreads ) throws Exception {
+               this.maxDepth = maxDepth;
+               dirList = new LinkedList();
+               dirList.add( new DirEntry( new SmbFile( dir ), maxDepth ));
+               for( int i = 0; i < numThreads; i++ ) {
+                       (new SmbCrawlerThread()).start();
+               }
+       }
+
+       public static void main(String[] argv) throws Exception {
+               if( argv.length < 3 ) {
+                       System.out.println( "usage: ThreadedSmbCrawler dir depth numThreads" );
+                       return;
+               }
+               Log.setMask( Log.CRITICAL_EXCEPTIONS );
+               new ThreadedSmbCrawler( argv[0], Integer.parseInt( argv[1] ), Integer.parseInt( argv[2] ));
+       }
+}
diff --git a/examples/TortureTest3.java b/examples/TortureTest3.java
new file mode 100644 (file)
index 0000000..b1a11b3
--- /dev/null
@@ -0,0 +1,86 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import java.util.*;
+import jcifs.smb.*;
+
+class TortureTest3 {
+
+       static final int NUM_OF_THREADS = 4;
+
+       java.util.List dirList;
+
+       TortureTest3() throws Exception {
+               dirList = Collections.synchronizedList( new LinkedList());
+       }
+
+       void execute() {
+               for( int i = 0; i < NUM_OF_THREADS; i++ ) {
+                       Thread t = new Worker( this );
+                       t.start();
+               }
+       }
+
+       class Worker extends Thread {
+               TortureTest3 con;
+               int count = 0;
+
+               Worker( TortureTest3 con ) {
+                       this.con = con;
+               }
+
+               public void run() {
+                       try {
+                               SmbFile dir, file;
+                               String[] list;
+                               while( true ) {
+                                       synchronized( con.dirList ) {
+                                               while( con.dirList.isEmpty() ) {
+                                                       con.dirList.wait( 100 );
+                                                       System.out.println( "name=" + getName() + ",count=" + count );
+                                               }
+                                               dir = (SmbFile)con.dirList.remove( 0 );
+                                       }
+                                       list = dir.list();
+                                       for( int i = 0; i < list.length; i++ ) {
+                                               file = new SmbFile( dir, list[i] );
+                                               if( file.isDirectory() ) {
+                                                       synchronized( con.dirList ) {
+                                                               con.dirList.add( file );
+                                                               con.dirList.notify();
+                                                       }
+                                                       System.out.println( "d " + file );
+                                               } else {
+                                                       count++;
+                                                       System.out.println( "  " + file );
+                                               }
+                                       }
+                               }
+                       } catch( Exception e ) {
+                               e.printStackTrace();
+                       }
+               }
+       }
+
+       public static void main( String argv[] ) throws Exception {
+               TortureTest3 con = new TortureTest3();
+               con.dirList.add( new SmbFile( argv[0] ));
+               con.execute();
+       }
+}
+
diff --git a/examples/TortureTest4.java b/examples/TortureTest4.java
new file mode 100644 (file)
index 0000000..c4f5318
--- /dev/null
@@ -0,0 +1,88 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.*;
+import jcifs.netbios.NbtAddress;
+import jcifs.util.*;
+import java.util.Enumeration;
+
+public class TortureTest4 extends Thread {
+
+       String url;
+       SmbFile file;
+
+       TortureTest4( String domain,
+                               String username,
+                               String password,
+                               String server,
+                               String share ) {
+
+               StringBuffer sb = new StringBuffer( "smb://" );
+
+               if( username != null ) {
+                       if( domain != null ) {
+                               sb.append( domain ).append( ';' );
+                       }
+                       sb.append( username );
+                       if( password != null ) {
+                               sb.append( ':' ).append( password );
+                       }
+                       sb.append( '@' );
+               }
+               sb.append( server + "/" + share + "/foo.txt" );
+
+               url = sb.toString();
+       }
+
+       public void run() {
+               try {
+System.out.println( "url=" + url );
+                       file = new SmbFile( url );
+                       file.exists();
+               } catch( Exception e ) {
+                       e.printStackTrace();
+               }
+       }
+
+       public static void main( String[] argv ) throws Exception {
+               Thread[] threads = new Thread[5];
+               String key;
+               Object val;
+               PropertiesTree shares = (PropertiesTree)jcifs.Config.get( argv[0] );
+               String server = shares.getProperty( "server" );
+               int i = 0;
+               for( Enumeration e = shares.keys(); e.hasMoreElements(); ) {
+                       key = (String)e.nextElement();
+                       val = shares.get( key );
+                       if( val instanceof PropertiesTree ) {
+                               threads[i++] = new TortureTest4( shares.getProperty( key + ".domain" ),
+                                                                                               shares.getProperty( key + ".username" ),
+                                                                                               shares.getProperty( key + ".password" ),
+                                                                                               server,
+                                                                                               key );
+                       }
+               }
+               for( int t = 0; t < i; t++ ) {
+                       threads[t].start();
+               }
+               for( int j = 0; j < i; j++ ) {
+                       threads[j].join();
+               }
+               System.exit( 0 );
+       }
+}
diff --git a/examples/TortureTest5.java b/examples/TortureTest5.java
new file mode 100644 (file)
index 0000000..efe80ed
--- /dev/null
@@ -0,0 +1,55 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.netbios.*;
+import java.util.Enumeration;
+
+public class TortureTest5 extends Thread {
+
+       String name;
+
+       TortureTest5( String name ) {
+               this.name = name;
+       }
+
+       public void run() {
+               try {
+                       System.out.println( NbtAddress.getByName( name ));
+               } catch( Exception e ) {
+                       e.printStackTrace();
+               }
+       }
+
+       public static void main( String[] argv ) throws Exception {
+       //      jcifs.util.Log.setMask( jcifs.util.Log.EXCEPTIONS | jcifs.util.Log.HEX_DUMPS );
+       //      jcifs.util.Config.setProperty( "retryCount", "1" );
+               jcifs.util.Config.setProperty( "soTimeout", "1000" );
+
+               Thread[] threads = new Thread[30];
+               for( int i = 0; i < argv.length; i++ ) {
+                       threads[i] = new TortureTest5( argv[i] );
+               }
+               for( int t = 0; t < argv.length; t++ ) {
+                       threads[t].start();
+               }
+               for( int j = 0; j < argv.length; j++ ) {
+                       threads[j].join();
+               }
+               System.exit( 0 );
+       }
+}
diff --git a/examples/TransactNamedPipe.java b/examples/TransactNamedPipe.java
new file mode 100644 (file)
index 0000000..7a1d4b1
--- /dev/null
@@ -0,0 +1,54 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License 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.
+ */
+
+import jcifs.smb.SmbNamedPipe;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
+public class TransactNamedPipe {
+
+       public static void main( String[] argv ) throws Exception {
+
+               if( argv.length < 2 ) {
+                       throw new IllegalArgumentException(
+                                               "args: <smburl> <filedatatosend> <filetowriterecvdata>" );
+               }
+
+               byte[] b = new byte[65535];
+               FileInputStream fin = new FileInputStream( argv[1] );
+               FileOutputStream fos = new FileOutputStream( argv[2] );
+
+               SmbNamedPipe pipe = new SmbNamedPipe( argv[0],
+                               SmbNamedPipe.PIPE_TYPE_RDWR | SmbNamedPipe.PIPE_TYPE_TRANSACT );
+               OutputStream out = pipe.getNamedPipeOutputStream();
+               InputStream in = pipe.getNamedPipeInputStream();
+
+               int n = fin.read( b );
+               System.out.println( "writing " + n + " bytes" );
+               out.write( b, 0, n );
+               n = in.read(b);
+               System.out.println( "read " + n + " bytes" );
+               fos.write(b, 0, n );
+
+               fin.close();
+               fos.close();
+               out.close();
+       }
+}
diff --git a/examples/jcifs.prp b/examples/jcifs.prp
new file mode 100644 (file)
index 0000000..24ec9dc
--- /dev/null
@@ -0,0 +1,7 @@
+# example jcifs properties tree file
+;baddr=192.168.1.255
+;domain=foo
+username=me
+password=bar
+;wins=146.123.82.22
+;log=all
diff --git a/examples/pipes/callnp.c b/examples/pipes/callnp.c
new file mode 100644 (file)
index 0000000..095eb0e
--- /dev/null
@@ -0,0 +1,123 @@
+/* examples for the jcifs smb client library in Java\r
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ * \r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+ */\r
+\r
+/* callnp.c - Call a Named Pipe\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <Windows.h>\r
+#include <stdlib.h>\r
+\r
+int\r
+hexstrtoi(const char *str)\r
+{\r
+       int i;\r
+       for (i = 0; str[i] != '\0'; i++) {\r
+               if (str[i] != 'x' && (str[i] < 48 || str[i] > 57)) {\r
+                       errno = 1;\r
+                       return 0;\r
+               }\r
+       }\r
+       return (int)strtol(str, NULL, 16);\r
+}\r
+\r
+int\r
+main(int argc, char *argv[])\r
+{\r
+       int i;\r
+       int bufferSize, timeout, bytesRead;\r
+       char *target, *send_buf, *recv_buf;\r
+       HANDLE inFile, outFile;\r
+\r
+       inFile = NULL;\r
+       outFile = NULL;\r
+       bufferSize = 65535;\r
+       bytesRead = 0;\r
+\r
+       if (argc == 1 || argv[1][1] == '\?') {\r
+               printf("defaults\r\n");\r
+               printf("  inFile     = <none>\r\n");\r
+               printf("  outFile    = <none>\r\n");\r
+               printf("  bufferSize = 65535\r\n");\r
+\r
+               printf("\r\ncallnp \\\\server\\pipe\\name /I inFile /O outFile /B bufferSize\r\n");\r
+\r
+               return 0;\r
+       }\r
+\r
+       if(argv[1][0] != '\\' && argv[1][1] != '\\') {\r
+               printf("Error: must specify target\r\n");\r
+       }\r
+       target = argv[1];\r
+       for(i = 2; i < argc; i++) {\r
+               if(argv[i][0] != '/') {\r
+                       printf("Error: invalid switch\r\n");\r
+               }\r
+               errno = 0;\r
+               switch(argv[i++][1]) {\r
+                       case 'I':\r
+                               inFile = CreateFile(argv[i], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); \r
+                               if(outFile == INVALID_HANDLE_VALUE) {\r
+                                       printf("Error: cannot open inFile: %s\r\n", argv[i]);\r
+                                       return 0;\r
+                               }\r
+                               break;\r
+                       case 'O':\r
+                               outFile = CreateFile(argv[i], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); \r
+                               if(outFile == INVALID_HANDLE_VALUE) {\r
+                                       printf("Error: cannot open outFile: %s\r\n", argv[i]);\r
+                                       return 0;\r
+                               }\r
+                               break;\r
+                       case 'B':\r
+                               bufferSize = atoi(argv[i]);\r
+                               break;\r
+                       default:\r
+                               printf("Error: no such option\r\n");\r
+                               return 0;\r
+               }\r
+               if(errno) {\r
+                       printf("Error: values must be in hex.\r\n");\r
+                       return 0;\r
+               }\r
+       }\r
+       send_buf = malloc(bufferSize);\r
+       recv_buf = malloc(bufferSize);\r
+       if(send_buf == NULL || recv_buf == NULL) {\r
+               printf("Error: failed to allocate buffers\r\n");\r
+               return 0;\r
+       }\r
+       if(inFile != NULL && ReadFile(inFile, send_buf, bufferSize, &bytesRead, NULL) == 0) {\r
+               printf("Error: failed to read from inFile\r\n");\r
+               return 0;\r
+       }\r
+       if (WaitNamedPipe(target, NMPWAIT_WAIT_FOREVER) == 0) {\r
+               printf("Error: WaitNamedPipe operation failed: %u\r\n", GetLastError());\r
+               return 0;\r
+       }\r
+       if (CallNamedPipe(target, send_buf, bytesRead, recv_buf, bufferSize, &bytesRead, NMPWAIT_WAIT_FOREVER) == 0) {\r
+               printf("Error: CallNamedPipe operation failed: %u\r\n", GetLastError());\r
+               return 0;\r
+       }\r
+       if(outFile != NULL && WriteFile(outFile, recv_buf, bytesRead, &bytesRead, NULL) == 0) {\r
+               printf("Error: failed to write to outFile\r\n");\r
+       }\r
+       printf("Success: operation performed successfully\r\n");\r
+       return 1;\r
+}\r
+\r
diff --git a/examples/pipes/callnp.exe b/examples/pipes/callnp.exe
new file mode 100644 (file)
index 0000000..679e9cf
Binary files /dev/null and b/examples/pipes/callnp.exe differ
diff --git a/examples/pipes/createf.c b/examples/pipes/createf.c
new file mode 100644 (file)
index 0000000..09e8d37
--- /dev/null
@@ -0,0 +1,208 @@
+/* examples for the jcifs smb client library in Java\r
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ * \r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+ */\r
+\r
+/* createf.c - Create a file with the CreateFile call.\r
+ */\r
+\r
+\r
+#include <stdio.h>\r
+#include <Windows.h>\r
+#include <stdlib.h>\r
+\r
+#define hexstrtoui(s) ((int)strtoul((s), NULL, 16))\r
+\r
+int\r
+main(int argc, char *argv[])\r
+{\r
+       int i;\r
+       int desiredAccess, shareMode, disposition, flags, bufferSize, bytesRead;\r
+       char *target, *buf;\r
+       HANDLE h, inFile, outFile;\r
+\r
+       inFile = NULL;\r
+       outFile = NULL;\r
+       desiredAccess = GENERIC_READ;\r
+       shareMode = 0;\r
+       disposition = CREATE_ALWAYS;\r
+       flags = FILE_ATTRIBUTE_NORMAL;\r
+       bufferSize = 65535;\r
+\r
+       if (argc == 1 || argv[1][1] == '\?') {\r
+\r
+               /* dwDesiredAccess\r
+                */\r
+               printf("dwDesiredAccess\r\n");\r
+               printf("  0x%08x GENERIC_READ\r\n", GENERIC_READ);\r
+               printf("  0x%08x GENERIC_WRITE\r\n", GENERIC_WRITE);\r
+               printf("  0x%08x DELETE\r\n", DELETE);\r
+               printf("  0x%08x READ_CONTROL\r\n", READ_CONTROL);\r
+               printf("  0x%08x WRITE_DAC\r\n", WRITE_DAC);\r
+               printf("  0x%08x WRITE_OWNER\r\n", WRITE_OWNER);\r
+               printf("  0x%08x SYNCHRONIZE\r\n", SYNCHRONIZE);\r
+               printf("  0x%08x STANDARD_RIGHTS_REQUIRED\r\n", STANDARD_RIGHTS_REQUIRED);\r
+               printf("  0x%08x STANDARD_RIGHTS_READ\r\n", STANDARD_RIGHTS_READ);\r
+               printf("  0x%08x STANDARD_RIGHTS_WRITE\r\n", STANDARD_RIGHTS_WRITE);\r
+               printf("  0x%08x STANDARD_RIGHTS_EXECUTE\r\n", STANDARD_RIGHTS_EXECUTE);\r
+               printf("  0x%08x STANDARD_RIGHTS_ALL\r\n", STANDARD_RIGHTS_ALL);\r
+               printf("  0x%08x SPECIFIC_RIGHTS_ALL\r\n", SPECIFIC_RIGHTS_ALL);\r
+               printf("  0x%08x ACCESS_SYSTEM_SECURITY\r\n", ACCESS_SYSTEM_SECURITY);\r
+               printf("  0x%08x MAXIMUM_ALLOWED\r\n", MAXIMUM_ALLOWED);\r
+               printf("  0x%08x GENERIC_EXECUTE\r\n", GENERIC_EXECUTE);\r
+               printf("  0x%08x GENERIC_ALL\r\n", GENERIC_ALL);\r
+               /* dwShareMode\r
+                */\r
+               printf("dwShareMode\n");\r
+               printf("  0x%08x FILE_SHARE_DELETE\r\n", FILE_SHARE_DELETE);\r
+               printf("  0x%08x FILE_SHARE_READ\r\n", FILE_SHARE_READ);\r
+               printf("  0x%08x FILE_SHARE_WRITE\r\n", FILE_SHARE_WRITE);\r
+               printf("  0x%08x the file cannot be shared\r\n", 0);\r
+               /* dwCreateDisposition\r
+                */\r
+               printf("dwCreateDisposition\r\n");\r
+               printf("  0x%08x CREATE_NEW\r\n", CREATE_NEW);\r
+               printf("  0x%08x CREATE_ALWAYS\r\n", CREATE_ALWAYS);\r
+               printf("  0x%08x OPEN_EXISTING\r\n", OPEN_EXISTING);\r
+               printf("  0x%08x OPEN_ALWAYS\r\n", OPEN_ALWAYS);\r
+               printf("  0x%08x TRUNCATE_EXISTING\r\n", TRUNCATE_EXISTING);\r
+               /* dwFlagsAndAttributes\r
+                */\r
+               printf("dwFlagsAndAttributes\r\n");\r
+               printf("  0x%08x FILE_ATTRIBUTE_ARCHIVE\r\n", FILE_ATTRIBUTE_ARCHIVE);\r
+               printf("  0x%08x FILE_ATTRIBUTE_ENCRYPTED\r\n", FILE_ATTRIBUTE_ENCRYPTED);\r
+               printf("  0x%08x FILE_ATTRIBUTE_HIDDEN\r\n", FILE_ATTRIBUTE_HIDDEN);\r
+               printf("  0x%08x FILE_ATTRIBUTE_NORMAL\r\n", FILE_ATTRIBUTE_NORMAL);\r
+               printf("  0x%08x FILE_ATTRIBUTE_NOT_CONTENT_INDEXED\r\n", FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);\r
+               printf("  0x%08x FILE_ATTRIBUTE_OFFLINE\r\n", FILE_ATTRIBUTE_OFFLINE);\r
+               printf("  0x%08x FILE_ATTRIBUTE_READONLY\r\n", FILE_ATTRIBUTE_READONLY);\r
+               printf("  0x%08x FILE_ATTRIBUTE_SYSTEM\r\n", FILE_ATTRIBUTE_SYSTEM);\r
+               printf("  0x%08x FILE_ATTRIBUTE_TEMPORARY\r\n", FILE_ATTRIBUTE_TEMPORARY);\r
+               \r
+               printf("  0x%08x FILE_FLAG_WRITE_THROUGH\r\n", FILE_FLAG_WRITE_THROUGH);\r
+               printf("  0x%08x FILE_FLAG_OVERLAPPED\r\n", FILE_FLAG_OVERLAPPED);\r
+               printf("  0x%08x FILE_FLAG_NO_BUFFERING\r\n", FILE_FLAG_NO_BUFFERING);\r
+               printf("  0x%08x FILE_FLAG_RANDOM_ACCESS\r\n", FILE_FLAG_RANDOM_ACCESS);\r
+               printf("  0x%08x FILE_FLAG_SEQUENTIAL_SCAN\r\n", FILE_FLAG_SEQUENTIAL_SCAN);\r
+               printf("  0x%08x FILE_FLAG_DELETE_ON_CLOSE\r\n", FILE_FLAG_DELETE_ON_CLOSE);\r
+               printf("  0x%08x FILE_FLAG_BACKUP_SEMANTICS\r\n", FILE_FLAG_BACKUP_SEMANTICS);\r
+               printf("  0x%08x FILE_FLAG_POSIX_SEMANTICS\r\n", FILE_FLAG_POSIX_SEMANTICS);\r
+               \r
+               printf("  0x%08x FILE_FLAG_OPEN_REPARSE_POINT\r\n", FILE_FLAG_OPEN_REPARSE_POINT);\r
+               printf("  0x%08x FILE_FLAG_OPEN_NO_RECALL\r\n", FILE_FLAG_OPEN_NO_RECALL);\r
+               printf("  0x%08x SECURITY_ANONYMOUS\r\n", SECURITY_ANONYMOUS);\r
+               printf("  0x%08x SECURITY_IDENTIFICATION\r\n", SECURITY_IDENTIFICATION);\r
+               printf("  0x%08x SECURITY_IMPERSONATION\r\n", SECURITY_IMPERSONATION);\r
+               printf("  0x%08x SECURITY_DELEGATION\r\n", SECURITY_DELEGATION);\r
+               printf("  0x%08x SECURITY_CONTEXT_TRACKING\r\n", SECURITY_CONTEXT_TRACKING);\r
+               printf("  0x%08x SECURITY_EFFECTIVE_ONLY\r\n", SECURITY_EFFECTIVE_ONLY);\r
+\r
+               printf("defaults\r\n");\r
+               printf("  dwDesiredAccess      = GENERIC_READ\r\n");\r
+               printf("  dwShareMode          = FILE_SHARE_READ\r\n");\r
+               printf("  dwCreateDisposition  = CREATE_ALWAYS\r\n");\r
+               printf("  dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL\r\n");\r
+               printf("  inFile               = none\r\n");\r
+               printf("  outFile              = none\r\n");\r
+               printf("  bufferSize           = 65535\r\n");\r
+\r
+               printf("\r\ncreatef \\\\server\\share\\path /A access /S share /D disposition /F flags /I inFile /O outFile /B bufferSize\r\n");\r
+\r
+               return 0;\r
+       }\r
+\r
+       if(argv[1][0] != '\\' && argv[1][1] != '\\') {\r
+               printf("Error: must specify target\r\n");\r
+       }\r
+       target = argv[1];\r
+       for(i = 2; i < argc; i++) {\r
+               if(argv[i][0] != '/') {\r
+                       printf("Error: invalid switch\r\n");\r
+               }\r
+               errno = 0;\r
+               switch(argv[i++][1]) {\r
+                       case 'A':\r
+                               desiredAccess = hexstrtoui(&argv[i][2]);\r
+                               break;\r
+                       case 'S':\r
+                               shareMode = hexstrtoui(argv[i]);\r
+                               break;\r
+                       case 'D':\r
+                               disposition = hexstrtoui(argv[i]);\r
+                               break;\r
+                       case 'F':\r
+                               flags = hexstrtoui(argv[i]);\r
+                               break;\r
+                       case 'I':\r
+                               inFile = CreateFile(argv[i], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); \r
+                               if(inFile == INVALID_HANDLE_VALUE) {\r
+                                       printf("Error: cannot open inFile: %s\r\n", argv[i]);\r
+                                       CloseHandle(outFile);\r
+                                       return 0;\r
+                               }\r
+                               break;\r
+                       case 'O':\r
+                               outFile = CreateFile(argv[i], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); \r
+                               if(outFile == INVALID_HANDLE_VALUE) {\r
+                                       printf("Error: cannot open outFile: %s\r\n", argv[i]);\r
+                                       CloseHandle(inFile);\r
+                                       return 0;\r
+                               }\r
+                               break;\r
+                       default:\r
+                               printf("Error: no such option\r\n");\r
+                               return 0;\r
+               }\r
+               if(errno) {\r
+                       printf("Error: %s\r\n", strerror(errno));\r
+                       return 0;\r
+               }\r
+       }\r
+\r
+       buf = malloc(bufferSize);\r
+       if(buf == NULL) {\r
+               printf("Error: failed to allocate buffer\r\n");\r
+               CloseHandle(inFile);\r
+               CloseHandle(outFile);\r
+               return 0;\r
+       }\r
+       h = CreateFile(target, desiredAccess, shareMode, NULL, disposition, flags, NULL);\r
+       if (h == INVALID_HANDLE_VALUE) {\r
+               printf("Error: CreateFile operation failed: %u\r\n", GetLastError());\r
+               CloseHandle(inFile);\r
+               CloseHandle(outFile);\r
+               return 0;\r
+       }\r
+       if(inFile != NULL || outFile != NULL) {\r
+               /* need to do reading or writing of some sort on the pipe */\r
+\r
+               if(inFile == NULL) {\r
+                       inFile = h;\r
+               }\r
+               if(outFile == NULL) {\r
+                       outFile = h;\r
+               }\r
+               while(ReadFile(inFile, buf, bufferSize, &bytesRead, NULL) > 0) {\r
+                       WriteFile(outFile, buf, bytesRead, &bytesRead, NULL);\r
+               }\r
+       }\r
+       printf("Success: operation performed successfully\r\n");\r
+       CloseHandle(inFile);\r
+       CloseHandle(outFile);\r
+       CloseHandle(h);\r
+       return 1;\r
+}\r
+\r
diff --git a/examples/pipes/createf.exe b/examples/pipes/createf.exe
new file mode 100644 (file)
index 0000000..77e4d2e
Binary files /dev/null and b/examples/pipes/createf.exe differ
diff --git a/examples/pipes/createnp.c b/examples/pipes/createnp.c
new file mode 100644 (file)
index 0000000..ca8c33d
--- /dev/null
@@ -0,0 +1,164 @@
+/* examples for the jcifs smb client library in Java\r
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ * \r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+ */\r
+\r
+/* createnp.c - Create a named pipe with CreateNamedPipe.\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <Windows.h>\r
+#include <stdlib.h>\r
+\r
+#define hexstrtoui(s) ((int)strtoul((s), NULL, 16))\r
+\r
+int\r
+main(int argc, char *argv[])\r
+{\r
+       int i;\r
+       int openMode, pipeMode, bufferSize, defaultTimeout, bytesRead;\r
+       char *target, *buf;\r
+       HANDLE h, inFile, outFile;\r
+\r
+       inFile = NULL;\r
+       outFile = NULL;\r
+       openMode = PIPE_ACCESS_DUPLEX;\r
+       pipeMode = PIPE_TYPE_BYTE | PIPE_WAIT;\r
+       bufferSize = 65535;\r
+\r
+       if (argc == 1 || argv[1][1] == '\?') {\r
+\r
+               /* dwOpenMode\r
+                */\r
+               printf("dwOpenMode\r\n");\r
+               printf("  0x%08x PIPE_ACCESS_DUPLEX\r\n", PIPE_ACCESS_DUPLEX);\r
+               printf("  0x%08x PIPE_ACCESS_INBOUND\r\n", PIPE_ACCESS_INBOUND);\r
+               printf("  0x%08x PIPE_ACCESS_OUTBOUND\r\n", PIPE_ACCESS_OUTBOUND);\r
+               printf("  0x%08x FILE_FLAG_WRITE_THROUGH\r\n", FILE_FLAG_WRITE_THROUGH);\r
+               printf("  0x%08x FILE_FLAG_OVERLAPPED\r\n", FILE_FLAG_OVERLAPPED);\r
+               printf("  0x%08x WRITE_DAC\r\n", WRITE_DAC);\r
+               printf("  0x%08x WRITE_OWNER\r\n", WRITE_OWNER);\r
+               printf("  0x%08x ACCESS_SYSTEM_SECURITY\r\n", ACCESS_SYSTEM_SECURITY);\r
+               /* dwPipeMode\r
+                */\r
+               printf("dwPipeMode\r\n");\r
+               printf("  0x%08x PIPE_TYPE_BYTE\r\n", PIPE_TYPE_BYTE);\r
+               printf("  0x%08x PIPE_TYPE_MESSAGE\r\n", PIPE_TYPE_MESSAGE);\r
+               printf("  0x%08x PIPE_READMODE_BYTE\r\n", PIPE_READMODE_BYTE);\r
+               printf("  0x%08x PIPE_READMODE_MESSAGE\r\n", PIPE_READMODE_MESSAGE);\r
+               printf("  0x%08x PIPE_WAIT\r\n", PIPE_WAIT);\r
+               printf("  0x%08x PIPE_NOWAIT\r\n", PIPE_NOWAIT);\r
+\r
+               printf("defaults\r\n");\r
+               printf("  inFile     = <read from pipe input>\r\n");\r
+               printf("  outFile    = <write to pipe output>\r\n");\r
+               printf("  dwOpenMode = PIPE_ACCESS_DUPLEX\r\n");\r
+               printf("  dwPipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT\r\n");\r
+               printf("  bufferSize = 65535\r\n");\r
+\r
+               printf("\r\ncreatenp \\\\.\\pipe\\name /I inFile /O outFile /M mode /P pmode /B bufferSize\r\n");\r
+\r
+               return 0;\r
+       }\r
+\r
+       if(argv[1][0] != '\\' && argv[1][1] != '\\') {\r
+               printf("Error: must specify target\r\n");\r
+       }\r
+       target = argv[1];\r
+       for(i = 2; i < argc; i++) {\r
+               if(argv[i][0] != '/') {\r
+                       printf("Error: invalid switch\r\n");\r
+               }\r
+               errno = 0;\r
+               switch(argv[i++][1]) {\r
+                       case 'I':\r
+                               inFile = CreateFile(argv[i], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); \r
+                               if(inFile == INVALID_HANDLE_VALUE) {\r
+                                       printf("Error: cannot open inFile: %s\r\n", argv[i]);\r
+                                       CloseHandle(outFile);\r
+                                       return 0;\r
+                               }\r
+                               break;\r
+                       case 'O':\r
+                               outFile = CreateFile(argv[i], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); \r
+                               if(outFile == INVALID_HANDLE_VALUE) {\r
+                                       printf("Error: cannot open outFile: %s\r\n", argv[i]);\r
+                                       CloseHandle(inFile);\r
+                                       return 0;\r
+                               }\r
+                               break;\r
+                       case 'M':\r
+                               openMode = hexstrtoui(argv[i]);\r
+                               break;\r
+                       case 'P':\r
+                               pipeMode = hexstrtoui(argv[i]);\r
+                               break;\r
+                       case 'B':\r
+                               bufferSize = atoi(argv[i]);\r
+                               break;\r
+                       default:\r
+                               printf("Error: no such option\r\n");\r
+                               CloseHandle(inFile);\r
+                               CloseHandle(outFile);\r
+                               return 0;\r
+               }\r
+               if(errno) {\r
+                       printf("Error: values must be in hex.\r\n");\r
+                       CloseHandle(inFile);\r
+                       CloseHandle(outFile);\r
+                       return 0;\r
+               }\r
+       }\r
+       h = CreateNamedPipe(target, openMode, pipeMode, 1, bufferSize, bufferSize, NMPWAIT_WAIT_FOREVER, NULL);\r
+       if (h == INVALID_HANDLE_VALUE) {\r
+               printf("Error: CreateNamedPipe operation failed: %u\r\n", GetLastError());\r
+               CloseHandle(inFile);\r
+               CloseHandle(outFile);\r
+               return 0;\r
+       }\r
+       if(ConnectNamedPipe(h, NULL) == 0 && GetLastError() != ERROR_PIPE_CONNECTED) {\r
+               printf("Error: ConnectNamedPipe operation failed: %u\r\n", GetLastError());\r
+               CloseHandle(inFile);\r
+               CloseHandle(outFile);\r
+               CloseHandle(h);\r
+               return 0;\r
+       }\r
+       buf = malloc(bufferSize);\r
+       if(buf == NULL) {\r
+               printf("Error: failed to allocate buffer\r\n");\r
+               CloseHandle(inFile);\r
+               CloseHandle(outFile);\r
+               DisconnectNamedPipe(h);\r
+               CloseHandle(h);\r
+               return 0;\r
+       }\r
+       if(inFile == NULL) {\r
+               inFile = h;\r
+       }\r
+       if(outFile == NULL) {\r
+               outFile = h;\r
+       }\r
+       while(ReadFile(inFile, buf, bufferSize, &bytesRead, NULL) > 0) {\r
+               WriteFile(outFile, buf, bytesRead, &bytesRead, NULL);\r
+       }\r
+       printf("Success: operation performed successfully\r\n");\r
+       CloseHandle(inFile);\r
+       CloseHandle(outFile);\r
+       DisconnectNamedPipe(h);\r
+       CloseHandle(h);\r
+       return 1;\r
+}\r
+\r
diff --git a/examples/pipes/createnp.exe b/examples/pipes/createnp.exe
new file mode 100644 (file)
index 0000000..248b1ad
Binary files /dev/null and b/examples/pipes/createnp.exe differ
diff --git a/examples/tt4.prp b/examples/tt4.prp
new file mode 100644 (file)
index 0000000..b36904d
--- /dev/null
@@ -0,0 +1,51 @@
+# config for TortureTest4
+
+;baddr=192.168.1.255
+wins=146.123.82.22
+;log=all
+
+<strauss>
+       server = strauss
+       username = goober
+       password = mypass
+       <download>
+               place = holder
+       </download>
+       <etc>
+               place = holder
+       </etc>
+       <temp>
+               username = someone
+               password = hello
+       </temp>
+</strauss>
+<hendrix>
+       server = hendrix
+       username = mike
+       password = x%43hhj
+       <temp>
+               place = holder
+       </temp>
+       <etc>
+               place = holder
+       </etc>
+       <My Documents>
+               place = holder
+       </My Documents>
+</hendrix>
+<fruit>
+       server = fruit
+       username = guest
+       password =
+       <orange>
+               place = holder
+       </orange>
+       <apple>
+               username = whooly
+               password = cranapple
+       </apple>
+       <grape>
+               username = gardner
+               password = hoe
+       </grape>
+</fruit>
diff --git a/examples/zzz.java b/examples/zzz.java
new file mode 100644 (file)
index 0000000..ba6b707
--- /dev/null
@@ -0,0 +1,44 @@
+
+import jcifs.smb.*;
+
+public class zzz implements Runnable
+{
+    public zzz()
+    {
+    }
+       public void run() {
+               try {
+                   SmbFile f = new SmbFile("smb://username:password@server/share/file.txt");
+                   SmbFileInputStream fin = new SmbFileInputStream(f);
+                       fin.close();
+               }
+               catch(Exception e) {
+                       e.printStackTrace();
+               }
+       }
+
+       static public void main(String args[]) {
+               jcifs.util.Config.setProperty( "wins", "146.123.82.22" );
+//             jcifs.util.Config.setProperty( "maxMpxCount", "1" );
+               int i,j;
+               int iterations = 1;
+               int numthreads = 100;
+               for(i=0; i<iterations; ++i)
+               {
+                       System.out.println("Iteration " + i);
+                       Thread threads[] = new Thread[numthreads];
+                       for(j=0; j<numthreads; ++j) {
+                               threads[j] = new Thread(new zzz());
+                               threads[j].start();
+                       }
+                       try {
+                               for(j=0; j<numthreads; ++j) {
+                                       threads[j].join();
+                               }
+                       } catch(InterruptedException e) {
+e.printStackTrace();
+                       }
+               }
+               System.out.println("Closing");
+       }
+}
diff --git a/src/jcifs/Config.java b/src/jcifs/Config.java
new file mode 100644 (file)
index 0000000..cfbf626
--- /dev/null
@@ -0,0 +1,121 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs;
+
+import jcifs.util.Log;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+
+/**
+ * This class extends the {@link jcifs.util.Config} class to simply add
+ * additional configuration information specific to the jcifs smb library.
+ * <p>
+ * See also <a href="../../overview-summary.html#scp">Setting JCIFS Properties</a>
+ */
+
+public class Config {
+
+       static {
+               Properties sys;
+               String mask;
+               String filename;
+               FileInputStream in = null;
+
+               sys = System.getProperties();
+               synchronized( sys ) {
+                       String pkgs = sys.getProperty( "java.protocol.handler.pkgs" );
+                       if( pkgs == null ) {
+                               pkgs = "jcifs";
+                       } else {
+                               pkgs += "|jcifs";
+                       }
+                       sys.put( "java.protocol.handler.pkgs", pkgs );
+               }
+
+               try {
+                       filename = sys.getProperty( "jcifs.properties" );
+                       if( filename != null && filename.length() > 1 ) {
+                               in = new FileInputStream( filename );
+                       }
+                       jcifs.util.Config.load( in );
+               } catch( IOException ioe ) {
+                       ioe.printStackTrace();
+               }
+
+               if(( mask = jcifs.util.Config.getProperty( "jcifs.util.log" )) != null ) {
+
+                       StringTokenizer st = new StringTokenizer( mask, "," );
+                       while( st.hasMoreTokens() ) {
+                               String s = st.nextToken().toUpperCase();
+                               if( s.startsWith( "ALL" )) {
+                                       Log.addMask( Log.ALL );
+                               } else if( s.startsWith( "EXC" )) {
+                                       Log.addMask( Log.EXCEPTIONS );
+                               } else if( s.startsWith( "WAR" )) {
+                                       Log.addMask( Log.WARNINGS );
+                               } else if( s.startsWith( "DEB" )) {
+                                       Log.addMask( Log.DEBUGGING );
+                               } else if( s.startsWith( "HEX" )) {
+                                       Log.addMask( Log.HEX_DUMPS );
+                               } else if( s.startsWith( "NON" )) {
+                                       Log.setMask( Log.NONE );
+                                       break;
+                               }
+                       }
+               }
+               jcifs.util.Config.printProperties( "properties loaded" );
+       }
+
+       public static void load( InputStream in ) throws IOException {
+               jcifs.util.Config.load( in );
+       }
+       public static void list( PrintStream out ) throws IOException {
+               jcifs.util.Config.list( out );
+       }
+       public static String setProperty( String key, String value ) {
+               return jcifs.util.Config.setProperty( key, value );
+       }
+       public static Object get( String key ) {
+               return jcifs.util.Config.get( key );
+       }
+       public static String getProperty( String key, String def ) {
+               return jcifs.util.Config.getProperty( key, def );
+       }
+       public static String getProperty( String key ) {
+               return jcifs.util.Config.getProperty( key );
+       }
+       public static int getInt( String key, int def ) {
+               return jcifs.util.Config.getInt( key, def );
+       }
+       public static int getInt( String key ) {
+               return jcifs.util.Config.getInt( key );
+       }
+       public static InetAddress getInetAddress( String key, InetAddress def ) {
+               return jcifs.util.Config.getInetAddress( key, def );
+       }
+       public static boolean getBoolean( String key, boolean def ) {
+               return jcifs.util.Config.getBoolean( key, def );
+       }
+}
+
diff --git a/src/jcifs/netbios/Lmhosts.java b/src/jcifs/netbios/Lmhosts.java
new file mode 100644 (file)
index 0000000..4fe8af4
--- /dev/null
@@ -0,0 +1,138 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import jcifs.Config;
+import jcifs.smb.SmbFileInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.net.UnknownHostException;
+
+class Lmhosts {
+
+       static String filename = Config.getProperty( "jcifs.netbios.lmhosts" );
+       static Hashtable tab = new Hashtable();
+       static long lastModified = 1L;
+       static int alt;
+
+       synchronized static NbtAddress getByName( Name name ) {
+               NbtAddress result = null;
+
+               try {
+                       if( filename != null ) {
+                               File f = new File( filename );
+                               long lm;
+
+                               if(( lm = f.lastModified() ) > lastModified ) {
+                                       lastModified = lm;
+                                       tab.clear();
+                                       alt = 0;
+                                       populate( new FileReader( f ));
+                               }
+                               result = (NbtAddress)tab.get( name );
+                       }
+               } catch( FileNotFoundException fnfe ) {
+                       Log.println( Log.WARNINGS, "netbios name service exception",
+                                                                       "lmhosts file not found: " + filename );
+               } catch( IOException ioe ) {
+                       Log.printStackTrace( "netbios name service exception", ioe );
+               }
+               return result;
+       }
+
+       static void populate( Reader r ) throws IOException {
+               String line;
+               BufferedReader br = new BufferedReader( r );
+
+               while(( line = br.readLine() ) != null ) {
+                       line = line.toUpperCase().trim();
+                       if( line.length() == 0 ) {
+                               continue;
+                       } else if( line.charAt( 0 ) == '#' ) {
+                               if( line.startsWith( "#INCLUDE " )) {
+                                       line = line.substring( line.indexOf( '\\' ));
+                                       String url = "smb:" + line.replace( '\\', '/' );
+
+                                       if( alt > 0 ) {
+                                               try {
+                                                       populate( new InputStreamReader( new SmbFileInputStream( url )));
+                                               } catch( IOException ioe ) {
+                                                       Log.println( Log.WARNINGS, "netbios name service warning",
+                                                                               "failed to load lmhosts alternate include: " + url );
+                                                       continue;
+                                               }
+
+                                               /* An include was loaded successfully. We can skip
+                                                * all other includes up to the #END_ALTERNATE tag.
+                                                */
+
+                                               alt--;
+                                               while(( line = br.readLine() ) != null ) {
+                                                       line = line.toUpperCase().trim();
+                                                       if( line.startsWith( "#END_ALTERNATE" )) {
+                                                               break;
+                                                       }
+                                               }
+                                       } else {
+                                               populate( new InputStreamReader( new SmbFileInputStream( url )));
+                                       }
+                               } else if( line.startsWith( "#BEGIN_ALTERNATE" )) {
+                                       alt++;
+                               } else if( line.startsWith( "#END_ALTERNATE" ) && alt > 0 ) {
+                                       alt--;
+                                       throw new IOException( "no lmhosts alternate includes loaded" );
+                               }
+                       } else if( Character.isDigit( line.charAt( 0 ))) {
+                               char[] data = line.toCharArray();
+                               int ip, i, j;
+                               Name name;
+                               NbtAddress addr;
+                               char c;
+
+                               c = '.';
+                               ip = i = 0;
+                               for( ; i < data.length && c == '.'; i++ ) {
+                                       int b = 0x00;
+
+                                       for( ; i < data.length && ( c = data[i] ) >= 48 && c <= 57; i++ ) {
+                                               b = b * 10 + c - '0';
+                                       }
+                                       ip = ( ip << 8 ) + b;
+                               }
+                               while( i < data.length && Character.isWhitespace( data[i] )) {
+                                       i++;
+                               }
+                               j = i;
+                               while( j < data.length && Character.isWhitespace( data[j] ) == false ) {
+                                       j++;
+                               }
+
+                               name = new Name( line.substring( i, j ), 0x20, null );
+                               addr = new NbtAddress( name, ip, false, NbtAddress.B_NODE );
+                               tab.put( name, addr );
+                       }
+               }
+       }
+}
diff --git a/src/jcifs/netbios/Log.java b/src/jcifs/netbios/Log.java
new file mode 100644 (file)
index 0000000..b881cc1
--- /dev/null
@@ -0,0 +1,117 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+/**
+ * Provides logging methods specific to the netbios package. Log class
+ * members are applied to the Log's mask(set as an arithmetic expression
+ * from {@link jcifs.util.Log#setMask(int mask)}) to "flip on" logging of
+ * netbios specific information.
+ * <p><blockquote><pre>
+ *     Log.setMask( Log.EXCEPTIONS +
+ *                 jcifs.netbios.Log.SESSION_SERVICE_PACKET_DATA );
+ * </pre></blockquote>
+ * <p>
+ * See the {@link jcifs.util.Log} parent class for details about this
+ * logging style.
+ *
+ * @version   0.1, 00/03/13
+ * @author    Michael B. Allen
+ * @see       jcifs.util.Log
+ * @since     jcifs-0.1
+ */
+
+public class Log extends jcifs.util.Log {
+
+    // supress javadoc constructor summary
+    Log() {}
+
+    public static final int NONE                        = 0xFFFFFF0F;
+    public static final int ALL                         = 0x000000F0;
+
+/**
+ *
+ * This mask produces limited netbios name service packet information. See
+ * <a href="http://www.cis.ohio-state.edu/rfc/rfc1002.txt">RFC 1002</a>
+ * for a detailed description of packet contents and their meaning.
+ * <p><blockquote><pre>
+ *  Mar 13 09:17:04 - name service packet
+ *   angus.mimosa.com/192.168.1.152:137 [62]
+ *   28887  Positive Name Query Response
+ *   authoritative answer,unicast,recursion desired,recursion available
+ * </pre></blockquote>
+ *
+ * @see jcifs.util.Log#setMask(int mask)
+ */
+
+    public static final int NAME_SERVICE_PACKET_DATA    = 0x00000010;
+
+    public static final int SESSION_SERVICE_PACKET_DATA = 0x00000020;
+
+/**
+ * This mask produces the contents of the netbios address cache.
+ *
+ * @see jcifs.util.Log#setMask(int mask)
+ */
+
+    public static final int ADDRESS_CACHE               = 0x00000040;
+
+/**
+ * reserved for this package
+ */
+    public static final int RESERVED8                   = 0x00000080;
+
+       static void printPacketData( String desc, SessionServicePacket ssp ) {
+               try {
+                       if(( SESSION_SERVICE_PACKET_DATA & mask ) == 0 ) {
+                               return;
+                       }
+            out.println( desc, ssp.toString() );
+        } catch( Exception e ) {
+            Log.printStackTrace( "jcifs.netbios.Log.printPacketData()", e );
+        }
+       }
+
+    static void printPacketData( String desc, NameServicePacket nsp ) {
+        try {
+            if(( NAME_SERVICE_PACKET_DATA & mask ) == 0 ) {
+                return;
+                       }
+                       out.println( desc, nsp.toString() );
+        } catch( Exception e ) {
+            Log.printStackTrace( "jcifs.netbios.Log.printPacketData()", e );
+        }
+    }
+    static void printAddressCache( String desc, Hashtable addressCache ) {
+        if(( ADDRESS_CACHE & mask ) == 0 )
+            return;
+        StringBuffer sb = new StringBuffer();
+        NbtAddress.CacheEntry ce;
+        for( Enumeration e = addressCache.elements(); e.hasMoreElements(); ) {
+            ce = (NbtAddress.CacheEntry)e.nextElement();
+            sb.append( ' ' ).append( ce.hostName );
+                       sb.append( ' ' ).append( ce.address ).append( NL );
+        }
+        out.println( desc, sb.toString() );
+    }
+}
+
diff --git a/src/jcifs/netbios/Name.java b/src/jcifs/netbios/Name.java
new file mode 100644 (file)
index 0000000..697149f
--- /dev/null
@@ -0,0 +1,200 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ *                     "Christopher R. Hertel" <crh@nts.umn.edu>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import jcifs.Config;
+
+class Name {
+
+    static final char[] HEX_DIGITS = { 
+    '0' , '1' , '2' , '3' , '4' , '5' ,
+    '6' , '7' , '8' , '9' , 'A' , 'B' ,
+    'C' , 'D' , 'E' , 'F'
+    };
+
+    static String toHexChars( int val ) {
+        int len = 2;
+        byte[] tmp = new byte[2];
+        while( len > 0 ) {
+            tmp[ len - 1 ] = (byte)HEX_DIGITS[ val & 0x000F ];
+            if( val != 0 ) {
+                val >>>= 4;
+            }
+            len--;
+        }
+        return new String( tmp );
+    }
+
+       static final int TYPE_OFFSET = 31;
+       static final int SCOPE_OFFSET = 33;
+
+       static String defaultScope = Config.getProperty( "jcifs.netbios.scope" );
+
+    String name, scope;
+    int type;
+
+    Name( String name, int type, String scope ) {
+               this.name = name;
+               this.type = type;
+               if( scope != null ) {
+                       this.scope = scope;
+               } else {
+                       this.scope = defaultScope;
+               }
+    }
+
+       int writeWireFormat( byte[] dst, int dstIndex ) {
+        // write 0x20 in first byte
+        dst[dstIndex] = 0x20;
+
+        // write name
+           name = ( name.length() > 15 ) ?
+                                                       name.substring( 0, 15 ).toUpperCase() :
+                                                       name.toUpperCase();
+        byte tmp[] = name.getBytes();
+        int i;
+        for( i = 0; i < tmp.length; i++ ) {
+            dst[dstIndex + ( 2 * i + 1 )] = (byte)((( tmp[i] & 0xF0 ) >> 4 ) + 0x41 );
+            dst[dstIndex + ( 2 * i + 2 )] = (byte)(( tmp[i] & 0x0F ) + 0x41 );
+        }
+        for( ; i < 15; i++ ) {
+            dst[dstIndex + ( 2 * i + 1 )] = (byte)0x43;
+            dst[dstIndex + ( 2 * i + 2 )] = (byte)0x41;
+        }
+        dst[dstIndex + TYPE_OFFSET] = (byte)((( type & 0xF0 ) >> 4 ) + 0x41 );
+        dst[dstIndex + TYPE_OFFSET + 1] = (byte)(( type & 0x0F ) + 0x41 );
+               return SCOPE_OFFSET + writeScopeWireFormat( dst, dstIndex + SCOPE_OFFSET );
+       }
+
+       int readWireFormat( byte[] src, int srcIndex ) {
+
+        byte tmp[] = new byte[SCOPE_OFFSET];
+        int length = 15;
+        for( int i = 0; i < 15; i++ ) {
+            tmp[i] = (byte)((( src[srcIndex + ( 2 * i + 1 )] & 0xFF ) - 0x41 ) << 4 );
+            tmp[i] |= (byte)((( src[srcIndex + ( 2 * i + 2 )] & 0xFF ) - 0x41 ) & 0x0F );
+            if( tmp[i] != (byte)' ' ) {
+                length = i + 1;
+            }
+        }
+        name = new String( tmp, 0, length );
+        type = (( src[srcIndex + TYPE_OFFSET] & 0xFF ) - 0x41 ) << 4;
+        type |= (( src[srcIndex + TYPE_OFFSET + 1] & 0xFF ) - 0x41 ) & 0x0F;
+               return SCOPE_OFFSET + readScopeWireFormat( src, srcIndex + SCOPE_OFFSET );
+    }
+       int writeScopeWireFormat( byte[] dst, int dstIndex ) {
+               if( scope == null || scope.length() == 0 ) {
+                       dst[dstIndex] = (byte)0x00;
+                       return 1;
+               }
+
+        // copy new scope in
+        dst[dstIndex++] = (byte)'.';
+        System.arraycopy( scope.getBytes(), 0, dst, dstIndex, scope.length() );
+               dstIndex += scope.length();
+
+               dst[dstIndex++] = (byte)0x00;
+
+        // now go over scope backwards converting '.' to label length
+
+               int i = dstIndex - 2;
+               int e = i - scope.length();
+               int c = 0;
+
+               do {
+            if( dst[i] == '.' ) {
+                dst[i] = (byte)c;
+                c = 0;
+            } else {
+                c++;
+            }
+               } while( i-- > e );
+               return scope.length() + 2;
+    }
+       int readScopeWireFormat( byte[] src, int srcIndex ) {
+               int start = srcIndex;
+               int n;
+
+               if(( n = src[srcIndex++] & 0xFF ) == 0 ) {
+                       scope = null;
+                       return 1;
+               }
+
+               StringBuffer sb = new StringBuffer( new String( src, srcIndex, n ));
+               srcIndex += n;
+               while(( n = src[srcIndex++] & 0xFF ) != 0 ) {
+                       sb.append( '.' ).append( new String( src, srcIndex, n ));
+                       srcIndex += n;
+               }
+               return srcIndex - start;
+       }
+
+    public int hashCode() {
+               int result = name.toUpperCase().hashCode();
+               result += 65599 * type;
+               if( scope != null && scope.length() != 0 ) {
+                       result += scope.hashCode();
+               }
+        return result;
+    }
+    public boolean equals( Object obj ) {
+        if( !( obj instanceof Name )) {
+            return false;
+        }
+        Name n = (Name)obj;
+        name = ( name.length() > 15 ) ?
+                                               name.substring( 0, 15 ).toUpperCase() :
+                                               name.toUpperCase();
+        n.name = ( n.name.length() > 15 ) ?
+                                               n.name.substring( 0, 15 ).toUpperCase() :
+                                               n.name.toUpperCase();
+               if(( scope == null || scope.length() == 0 ) &&
+                               ( n.scope == null || n.scope.length() == 0 )) {
+                       return name.equals( n.name ) && type == n.type;
+               }
+               return name.equals( n.name ) && type == n.type && scope.equals( n.scope );
+    }
+       String getName() {
+        return ( name.length() > 15 ) ?
+                                               name.substring( 0, 15 ).toUpperCase() :
+                                               name.toUpperCase();
+       }
+    public String toString() {
+               StringBuffer sb = new StringBuffer();
+               String n = getName();
+
+        // fix MSBROWSE name
+        if( n.charAt( 0 ) == 0x01 ) {
+            byte b[] = n.getBytes();
+            b[0] = (byte)'.';
+            b[1] = (byte)'.';
+            b[14] = (byte)'.';
+            n = new String( b );
+        }
+
+        sb.append( n ).append( "<" ).append( toHexChars( type )).append( ">" );
+        if( scope != null && scope.length() != 0 ) {
+            sb.append( "." ).append( scope );
+        }
+        return sb.toString();
+    }
+
+}
+
diff --git a/src/jcifs/netbios/NameQueryRequest.java b/src/jcifs/netbios/NameQueryRequest.java
new file mode 100644 (file)
index 0000000..3bdc0a9
--- /dev/null
@@ -0,0 +1,44 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+class NameQueryRequest extends NameServicePacket {
+
+       NameQueryRequest( Name name ) {
+               questionName = name;
+               questionType = NB;
+       }
+
+       int writeBodyWireFormat( byte[] dst, int dstIndex ) {
+               return writeQuestionSectionWireFormat( dst, dstIndex );
+       }
+       int readBodyWireFormat( byte[] src, int srcIndex ) {
+               return readQuestionSectionWireFormat( src, srcIndex );
+       }
+       int writeRDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readRDataWireFormat( byte[] src, int srcIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "NameQueryRequest[" +
+                       super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/netbios/NameQueryResponse.java b/src/jcifs/netbios/NameQueryResponse.java
new file mode 100644 (file)
index 0000000..dd67797
--- /dev/null
@@ -0,0 +1,54 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+class NameQueryResponse extends NameServicePacket {
+
+       NbtAddress addrEntry;
+
+       NameQueryResponse() {
+               recordName = new Name( null, 0, null );
+       }
+
+       int writeBodyWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readBodyWireFormat( byte[] src, int srcIndex ) {
+               return readResourceRecordWireFormat( src, srcIndex );
+       }
+       int writeRDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readRDataWireFormat( byte[] src, int srcIndex ) {
+               if( resultCode != 0 || opCode != QUERY ) {
+                       return 0;
+               }
+               boolean groupName = (( src[srcIndex] & 0x80 ) == 0x80 ) ? true : false;
+               int nodeType = ( src[srcIndex] & 0x60 ) >> 5;
+               srcIndex += 2;
+               int address = readInt4( src, srcIndex );
+               addrEntry = new NbtAddress( recordName, address, groupName, nodeType );
+               return 6;
+       }
+       public String toString() {
+               return new String( "NameQueryResponse[" +
+                       super.toString() +
+                       ",addrEntry=" + addrEntry + "]" );
+       }
+}
diff --git a/src/jcifs/netbios/NameServiceClient.java b/src/jcifs/netbios/NameServiceClient.java
new file mode 100644 (file)
index 0000000..327fe02
--- /dev/null
@@ -0,0 +1,329 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import java.net.InetAddress;
+import java.net.DatagramSocket;
+import java.net.DatagramPacket;
+import java.net.UnknownHostException;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import jcifs.Config;
+
+class NameServiceClient implements Runnable {
+
+    static final int DEFAULT_SO_TIMEOUT = 5000;
+    static final int DEFAULT_RCV_BUF_SIZE = 576;
+    static final int DEFAULT_SND_BUF_SIZE = 576;
+       static final int NAME_SERVICE_UDP_PORT = 137;
+       static final int DEFAULT_RETRY_COUNT = 2;
+       static final int DEFAULT_RETRY_TIMEOUT = 3000;
+
+       static final int RESOLVER_WINS    = 0;
+       static final int RESOLVER_BCAST   = 1;
+       static final int RESOLVER_DNS     = 2;
+       static final int RESOLVER_LMHOSTS = 3;
+
+       NbtAddress localhost;
+    InetAddress laddr, baddr, nbns;
+    int port, soTimeout, retryCount, retryTimeout, closeTimeout;
+    int snd_buf_size, rcv_buf_size;
+    byte[] snd_buf, rcv_buf;
+    DatagramSocket socket;
+    DatagramPacket in, out;
+       Hashtable responseTable;
+    Thread thread;
+       int nextNameTrnId;
+       Object socketLock;
+       int[] resolveOrder;
+
+       NameServiceClient() {
+               this( Config.getInt( "jcifs.netbios.lport", 0 ),
+                       Config.getInetAddress( "jcifs.netbios.laddr", null ));
+       }
+    NameServiceClient( int port, InetAddress laddr ) {
+        this.port = port;
+        this.laddr = laddr;
+
+               try {
+                       baddr = Config.getInetAddress( "jcifs.netbios.baddr",
+                                               InetAddress.getByName( "255.255.255.255" ));
+
+                       InetAddress inet = laddr;
+                       if( inet == null ) {
+                               inet = InetAddress.getLocalHost();
+                       }
+                       String name = Config.getProperty( "jcifs.netbios.hostname", null );
+                       if( name == null || name.length() == 0 ) {
+                               byte[] addr = inet.getAddress();
+                               name = "JCIFS" +
+                                               ( addr[2] & 0xFF ) + "_" +
+                                               ( addr[3] & 0xFF ) + "_" +
+                                               Name.toHexChars( (int)( Math.random() * (double)0xFF ));
+                       }
+                       localhost = NbtAddress.getByName( inet.getHostAddress(),
+                                               0x00, Config.getProperty( "jcifs.netbios.scope", null ));
+                       localhost.hostName.name = name;
+                       NbtAddress.cacheAddress( localhost.hostName, localhost, NbtAddress.FOREVER );
+               } catch( UnknownHostException uhe ) {
+               }
+
+               nbns = Config.getInetAddress( "jcifs.netbios.wins", null );
+
+               String ro = Config.getProperty( "jcifs.netbios.resolveOrder" );
+               if( ro == null || ro.length() == 0 ) {
+
+                       /* No resolveOrder has been specified, use the
+                        * default which is LMHOSTS,WINS,BCAST,DNS or just
+                        * LMHOSTS,BCAST,DNS if jcifs.netbios.wins has not
+                        * been specified.
+                        */
+
+                       if( nbns == null ) {
+                               resolveOrder = new int[3];
+                               resolveOrder[0] = RESOLVER_LMHOSTS;
+                               resolveOrder[1] = RESOLVER_BCAST;
+                               resolveOrder[2] = RESOLVER_DNS;
+                       } else {
+                               resolveOrder = new int[4];
+                               resolveOrder[0] = RESOLVER_LMHOSTS;
+                               resolveOrder[1] = RESOLVER_WINS;
+                               resolveOrder[2] = RESOLVER_BCAST;
+                               resolveOrder[3] = RESOLVER_DNS;
+                       }
+               } else {
+                       int[] tmp = new int[4];
+                       StringTokenizer st = new StringTokenizer( ro, "," );
+                       int i = 0;
+                       while( st.hasMoreTokens() ) {
+                               String s = st.nextToken().trim();
+                               if( s.equalsIgnoreCase( "LMHOSTS" )) {
+                                       tmp[i++] = RESOLVER_LMHOSTS;
+                               } else if( s.equalsIgnoreCase( "WINS" )) {
+                                       if( nbns == null ) {
+                                               Log.println( Log.WARNINGS, "netbios name service warning",
+                                                               " resolveOrder specifies WINS however the " +
+                                                               "jcifs.netbios.wins property has not been set" );
+                                               continue;
+                                       }
+                                       tmp[i++] = RESOLVER_WINS;
+                               } else if( s.equalsIgnoreCase( "BCAST" )) {
+                                       tmp[i++] = RESOLVER_BCAST;
+                               } else if( s.equalsIgnoreCase( "DNS" )) {
+                                       tmp[i++] = RESOLVER_DNS;
+                               } else {
+                                       Log.println( Log.WARNINGS, "netbios name service warning",
+                                                               "unknown resolver method: " + s );
+                               }
+                       }
+                       resolveOrder = new int[i];
+                       System.arraycopy( tmp, 0, resolveOrder, 0, i );
+               }
+
+        soTimeout = Config.getInt( "jcifs.netbios.soTimeout", DEFAULT_SO_TIMEOUT );
+               retryCount = Config.getInt( "jcifs.netbios.retryCount", DEFAULT_RETRY_COUNT );
+               retryTimeout = Config.getInt( "jcifs.netbios.retryTimeout", DEFAULT_RETRY_TIMEOUT);
+        rcv_buf_size = Config.getInt( "jcifs.netbios.rcv_buf_size", DEFAULT_RCV_BUF_SIZE );
+        snd_buf_size = Config.getInt( "jcifs.netbios.snd_buf_size", DEFAULT_SND_BUF_SIZE );
+        rcv_buf = new byte[rcv_buf_size];
+        snd_buf = new byte[snd_buf_size];
+        in  = new DatagramPacket( rcv_buf, rcv_buf_size );
+        out = new DatagramPacket( snd_buf, snd_buf_size, baddr, NAME_SERVICE_UDP_PORT );
+               responseTable = new Hashtable();
+               nextNameTrnId = 0;
+               socketLock = new Object();
+    }
+
+       int getNextNameTrnId() {
+               if(( ++nextNameTrnId & 0xFFFF ) == 0 ) {
+                       nextNameTrnId = 1;
+               }
+               return nextNameTrnId;
+       }
+    void ensureOpen( int timeout ) throws IOException {
+               closeTimeout = 0;
+               if( soTimeout != 0 ) {
+                       closeTimeout = Math.max( soTimeout, timeout );
+               }
+               // If socket is still good, the new closeTimeout will
+               // be ignored; see tryClose comment.
+        if( socket == null ) {
+               socket = new DatagramSocket( port, laddr );
+               thread = new Thread( this );
+                       thread.setDaemon( true );
+               thread.start();
+               }
+    }
+    void tryClose() {
+               synchronized( socketLock ) {
+
+                       /* Yes, there is the potential to drop packets
+                        * because we might close the socket during a
+                        * request. However the chances are slim and the
+                        * retry code should ensure the overall request
+                        * is serviced. The alternative complicates things
+                        * more than I think is worth it.
+                        */
+
+               if( socket != null ) {
+                       socket.close();
+                       socket = null;
+               }
+               thread = null;
+                       responseTable.clear();
+               }
+    }
+    public void run() {
+               int nameTrnId;
+               NameServicePacket response;
+
+        while( thread == Thread.currentThread() ) {
+                       in.setLength( rcv_buf_size );
+               try {
+                       socket.setSoTimeout( closeTimeout );
+               socket.receive( in );
+               } catch( IOException ioe ) {
+                               tryClose();
+                               continue;
+               }
+
+                       Log.println( Log.DEBUGGING, "nbt name service debugging",
+                                                                                                       " new data read from socket" );
+
+                       nameTrnId = NameServicePacket.readNameTrnId( rcv_buf, 0 );
+                       response = (NameServicePacket)responseTable.get( new Integer( nameTrnId ));
+                       if( response == null || response.received ) {
+                               continue;
+                       }
+                       synchronized( response ) {
+                               response.readWireFormat( rcv_buf, 0 );
+                               response.received = true;
+
+                               Log.printPacketData( "nbt name service packet receviced", response );
+                               Log.printHexDump( "datagram packet received from: " +
+                                               in.getAddress().toString(), rcv_buf, 0, in.getLength() );
+
+                               response.notify();
+                       }
+        }
+    }
+    void send( NameServicePacket request,
+                                       NameServicePacket response, int timeout ) throws IOException {
+               Integer nid = null;
+
+               synchronized( response ) {
+                       try {
+                               synchronized( socketLock ) {
+                                       request.nameTrnId = getNextNameTrnId();
+                                       nid = new Integer( request.nameTrnId );
+
+                               out.setAddress( request.addr );
+                               out.setLength( request.writeWireFormat( snd_buf, 0 ));
+                                       response.received = false;
+
+                                       responseTable.put( nid, response );
+                               ensureOpen( timeout + 1000 );
+                           socket.send( out );
+
+                                       Log.printPacketData( "nbt name service packet sent", request );
+                                       Log.printHexDump( "datagram packet sent to: " +
+                                                               out.getAddress().toString(), snd_buf, 0, out.getLength() );
+                               }
+
+                               response.wait( timeout );
+
+                       } catch( InterruptedException ie ) {
+                       } finally {
+                               responseTable.remove( nid );
+                       }
+               }
+    }
+       NbtAddress getByName( Name name ) throws UnknownHostException {
+               NameQueryRequest request = new NameQueryRequest( name );
+               NameQueryResponse response = new NameQueryResponse();
+
+               for( int i = 0; i < resolveOrder.length; i++ ) {
+                       try {
+                               switch( resolveOrder[i] ) {
+                                       case RESOLVER_LMHOSTS:
+                                               NbtAddress ans = Lmhosts.getByName( name );
+                                               if( ans != null ) {
+                                                       return ans;
+                                               }
+                                               break;
+                                       case RESOLVER_WINS:
+                                       case RESOLVER_BCAST:
+                                               if( resolveOrder[i] == RESOLVER_WINS &&
+                                                               nbns != null &&
+                                                               name.name != NbtAddress.MASTER_BROWSER_NAME &&
+                                                               name.type != 0x1d ) {
+                                                       request.addr = nbns;
+                                                       request.isBroadcast = false;
+                                               } else {
+                                                       request.addr = baddr;
+                                                       request.isBroadcast = true;
+                                               }
+
+                                               int n = retryCount;
+                                               while( n-- > 0 ) {
+                                                       try {
+                                                               send( request, response, retryTimeout );
+                                                       } catch( IOException ioe ) {
+                                                               Log.printStackTrace( "nbt name service send:", ioe );
+                                                               throw new UnknownHostException( ioe.getMessage() );
+                                                       }
+                                                       if( response.received && response.resultCode == 0 ) {
+                                                               return response.addrEntry;
+                                                       }
+                                               }
+                                               break;
+                                       case RESOLVER_DNS:
+                                               if( name.type == 0x20 || name.type == 0x00 ) {
+                                                       InetAddress addr = InetAddress.getByName( name.name );
+                                                       return new NbtAddress( new Name( NbtAddress.ALL_HOSTS_NAME,
+                                                                               name.type, name.scope ), addr.hashCode(), false,
+                                                                               NbtAddress.B_NODE );
+                                               }
+                               }
+                       } catch( IOException ioe ) {
+                       }
+               }
+               throw new UnknownHostException( name.name );
+       }
+       NbtAddress[] getNodeStatus( NbtAddress addr ) throws UnknownHostException {
+               NodeStatusRequest request = new NodeStatusRequest( addr.hostName );
+               NodeStatusResponse response = new NodeStatusResponse( addr );
+               request.addr = addr.getInetAddress();
+               int n = retryCount;
+               while( n-- > 0 ) {
+                       try {
+                               send( request, response, retryTimeout );
+                       } catch( IOException ioe ) {
+                               Log.printStackTrace( "nbt name service send:", ioe );
+                               throw new UnknownHostException( ioe.getMessage() );
+                       }
+                       if( response.received && response.resultCode == 0 ) {
+                               return response.addressArray;
+                       }
+               }
+               throw new UnknownHostException( addr.hostName.name );
+       }
+}
diff --git a/src/jcifs/netbios/NameServicePacket.java b/src/jcifs/netbios/NameServicePacket.java
new file mode 100644 (file)
index 0000000..f3e455f
--- /dev/null
@@ -0,0 +1,318 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import java.net.InetAddress;
+
+abstract class NameServicePacket {
+
+       // opcode
+       static final int QUERY = 0;
+       static final int WACK = 7;
+
+       // rcode
+       static final int FMT_ERR = 0x1;
+       static final int SRV_ERR = 0x2;
+       static final int IMP_ERR = 0x4;
+       static final int RFS_ERR = 0x5;
+       static final int ACT_ERR = 0x6;
+       static final int CFT_ERR = 0x7;
+
+       // type/class
+       static final int NB_IN     = 0x00200001;
+       static final int NBSTAT_IN = 0x00210001;
+       static final int NB        = 0x0020;
+       static final int NBSTAT    = 0x0021;
+       static final int IN        = 0x0001;
+       static final int A         = 0x0001;
+       static final int NS        = 0x0002;
+       static final int NULL      = 0x000a;
+
+       static final int HEADER_LENGTH = 12;
+
+       // header field offsets
+       static final int OPCODE_OFFSET = 2;
+       static final int QUESTION_OFFSET = 4;
+       static final int ANSWER_OFFSET = 6;
+       static final int AUTHORITY_OFFSET = 8;
+       static final int ADDITIONAL_OFFSET = 10;
+
+       static void writeInt2( int val, byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = (byte)(( val >> 8 ) & 0xFF );
+               dst[dstIndex] = (byte)( val & 0xFF );
+       }
+       static void writeInt4( int val, byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = (byte)(( val >> 24 ) & 0xFF );
+               dst[dstIndex++] = (byte)(( val >> 16 ) & 0xFF );
+               dst[dstIndex++] = (byte)(( val >> 8 ) & 0xFF );
+               dst[dstIndex] = (byte)( val & 0xFF );
+       }
+       static int readInt2( byte[] src, int srcIndex ) {
+               return (( src[srcIndex] & 0xFF ) << 8 ) +
+                               ( src[srcIndex + 1] & 0xFF );
+       }
+       static int readInt4( byte[] src, int srcIndex ) {
+               return (( src[srcIndex] & 0xFF ) << 24 ) +
+                               (( src[srcIndex + 1] & 0xFF ) << 16 ) +
+                               (( src[srcIndex + 2] & 0xFF ) << 8 ) +
+                               ( src[srcIndex + 3] & 0xFF );
+       }
+
+       static int readNameTrnId( byte[] src, int srcIndex ) {
+               return readInt2( src, srcIndex );
+       }
+
+       int nameTrnId;
+
+       int opCode,
+                       resultCode,
+                       questionCount,
+                       answerCount,
+                       authorityCount,
+                       additionalCount;
+       boolean received,
+                       isResponse,
+                       isAuthAnswer,
+                       isTruncated,
+                       isRecurDesired,
+                       isRecurAvailable,
+                       isBroadcast;
+
+       Name questionName;
+       Name recordName;
+
+       int questionType,
+                       questionClass,
+                       recordType,
+                       recordClass,
+                       ttl,
+                       rDataLength;
+
+       InetAddress addr;
+
+       NameServicePacket() {
+               isRecurDesired = true;
+               isBroadcast = true;
+               questionCount = 1;
+               questionClass = IN;
+       }
+
+       int writeWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+               dstIndex += writeHeaderWireFormat( dst, dstIndex );
+               dstIndex += writeBodyWireFormat( dst, dstIndex );
+               return dstIndex - start;
+       }
+       int readWireFormat( byte[] src, int srcIndex ) {
+               int start = srcIndex;
+               srcIndex += readHeaderWireFormat( src, srcIndex );
+               srcIndex += readBodyWireFormat( src, srcIndex );
+               return srcIndex - start;
+       }
+
+       int writeHeaderWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+               writeInt2( nameTrnId, dst, dstIndex );
+               dst[dstIndex + OPCODE_OFFSET] = (byte)(( isResponse ? 0x80 : 0x00 ) +
+                                               (( opCode << 3 ) & 0x78 ) +
+                                               ( isAuthAnswer ? 0x04 : 0x00 ) +
+                                               ( isTruncated ? 0x02 : 0x00 ) +
+                                               ( isRecurDesired ? 0x01 : 0x00 ));
+               dst[dstIndex + OPCODE_OFFSET + 1] = (byte)(( isRecurAvailable ? 0x80 : 0x00 ) +
+                                               ( isBroadcast ? 0x10 : 0x00 ) +
+                                               ( resultCode & 0x0F ));
+               writeInt2( questionCount, dst, start + QUESTION_OFFSET );
+               writeInt2( answerCount, dst, start + ANSWER_OFFSET );
+               writeInt2( authorityCount, dst, start + AUTHORITY_OFFSET );
+               writeInt2( additionalCount, dst, start + ADDITIONAL_OFFSET );
+               return HEADER_LENGTH;
+       }
+       int readHeaderWireFormat( byte[] src, int srcIndex ) {
+               nameTrnId       = readInt2( src, srcIndex );
+        isResponse      = (( src[srcIndex + OPCODE_OFFSET] & 0x80 ) == 0 ) ? false : true;
+               opCode          = ( src[srcIndex + OPCODE_OFFSET] & 0x78 ) >> 3;
+               isAuthAnswer    = (( src[srcIndex + OPCODE_OFFSET] & 0x04 ) == 0 ) ? false : true;
+               isTruncated     = (( src[srcIndex + OPCODE_OFFSET] & 0x02 ) == 0 ) ? false : true;
+        isRecurDesired  = (( src[srcIndex + OPCODE_OFFSET] & 0x01 ) == 0 ) ? false : true;
+        isRecurAvailable =
+                                               (( src[srcIndex + OPCODE_OFFSET + 1] & 0x80 ) == 0 ) ? false : true;
+        isBroadcast     = (( src[srcIndex + OPCODE_OFFSET + 1] & 0x10 ) == 0 ) ? false : true;
+        resultCode      = src[srcIndex + OPCODE_OFFSET + 1] & 0x0F;
+               questionCount   = readInt2( src, srcIndex + QUESTION_OFFSET );
+               answerCount     = readInt2( src, srcIndex + ANSWER_OFFSET );
+               authorityCount  = readInt2( src, srcIndex + AUTHORITY_OFFSET );
+               additionalCount = readInt2( src, srcIndex + ADDITIONAL_OFFSET );
+               return HEADER_LENGTH;
+       }
+       int writeQuestionSectionWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+               dstIndex += questionName.writeWireFormat( dst, dstIndex );
+               writeInt2( questionType, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( questionClass, dst, dstIndex );
+               dstIndex += 2;
+               return dstIndex - start;
+       }
+       int readQuestionSectionWireFormat( byte[] src, int srcIndex ) {
+               int start = srcIndex;
+               srcIndex += questionName.readWireFormat( src, srcIndex );
+               questionType = readInt2( src, srcIndex );
+               srcIndex += 2;
+               questionClass = readInt2( src, srcIndex );
+               srcIndex += 2;
+               return srcIndex - start;
+       }
+       int writeResourceRecordWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+               if( recordName == questionName ) {
+                       dst[dstIndex++] = (byte)0xC0; // label string pointer to
+                       dst[dstIndex++] = (byte)0x0C; // questionName (offset 12)
+               } else {
+                       dstIndex += recordName.writeWireFormat( dst, dstIndex );
+               }
+               writeInt2( recordType, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( recordClass, dst, dstIndex );
+               dstIndex += 2;
+               writeInt4( ttl, dst, dstIndex );
+               dstIndex += 4;
+               rDataLength = writeRDataWireFormat( dst, dstIndex + 2 );
+               writeInt2( rDataLength, dst, dstIndex );
+               dstIndex += 2 + rDataLength;
+               return dstIndex - start;
+       }
+       int readResourceRecordWireFormat( byte[] src, int srcIndex ) {
+               int start = srcIndex;
+               if(( src[srcIndex] & 0xC0 ) == 0xC0 ) {
+                       recordName = questionName; // label string pointer to questionName
+                       srcIndex += 2;
+               } else {
+                       srcIndex += recordName.readWireFormat( src, srcIndex );
+               }
+               recordType = readInt2( src, srcIndex );
+               srcIndex += 2;
+               recordClass = readInt2( src, srcIndex );
+               srcIndex += 2;
+               ttl = readInt4( src, srcIndex );
+               srcIndex += 4;
+               rDataLength = readInt2( src, srcIndex );
+               srcIndex += 2;
+               readRDataWireFormat( src, srcIndex );
+               srcIndex += rDataLength;
+               return srcIndex - start;
+       }
+
+       abstract int writeBodyWireFormat( byte[] dst, int dstIndex );
+       abstract int readBodyWireFormat( byte[] src, int srcIndex );
+       abstract int writeRDataWireFormat( byte[] dst, int dstIndex );
+       abstract int readRDataWireFormat( byte[] src, int srcIndex );
+
+       public String toString() {
+               String opCodeString,
+                               resultCodeString,
+                               questionTypeString,
+                               questionClassString,
+                               recordTypeString,
+                               recordClassString;
+
+               switch( opCode ) {
+                       case QUERY:
+                               opCodeString = "QUERY";
+                               break;
+                       case WACK:
+                               opCodeString = "WACK";
+                               break;
+                       default:
+                               opCodeString = Integer.toString( opCode );
+               }
+               switch( resultCode ) {
+                       case FMT_ERR:
+                               resultCodeString = "FMT_ERR";
+                               break;
+                       case SRV_ERR:
+                               resultCodeString = "SRV_ERR";
+                               break;
+                       case IMP_ERR:
+                               resultCodeString = "IMP_ERR";
+                               break;
+                       case RFS_ERR:
+                               resultCodeString = "RFS_ERR";
+                               break;
+                       case ACT_ERR:
+                               resultCodeString = "ACT_ERR";
+                               break;
+                       case CFT_ERR:
+                               resultCodeString = "CFT_ERR";
+                               break;
+                       default:
+                               resultCodeString = "0x" + Log.getHexString( resultCode, 1 );
+               }
+               switch( questionType ) {
+                       case NB:
+                               questionTypeString = "NB";
+                       case NBSTAT:
+                               questionTypeString = "NBSTAT";
+                       default:
+                               questionTypeString = "0x" + Log.getHexString( questionType, 4 );
+               }
+               switch( recordType ) {
+                       case A:
+                               recordTypeString = "A";
+                               break;
+                       case NS:
+                               recordTypeString = "NS";
+                               break;
+                       case NULL:
+                               recordTypeString = "NULL";
+                               break;
+                       case NB:
+                               recordTypeString = "NB";
+                       case NBSTAT:
+                               recordTypeString = "NBSTAT";
+                       default:
+                               recordTypeString = "0x" + Log.getHexString( recordType, 4 );
+               }
+
+               return new String(
+                               "nameTrnId=" + nameTrnId +
+                               ",isResponse=" + isResponse +
+                               ",opCode=" + opCodeString +
+                               ",isAuthAnswer=" + isAuthAnswer +
+                               ",isTruncated=" + isTruncated +
+                               ",isRecurAvailable=" + isRecurAvailable +
+                               ",isRecurDesired=" + isRecurDesired +
+                               ",isBroadcast=" + isBroadcast +
+                               ",resultCode=" + resultCode +
+                               ",questionCount=" + questionCount +
+                               ",answerCount=" + answerCount +
+                               ",authorityCount=" + authorityCount +
+                               ",additionalCount=" + additionalCount +
+                               ",questionName=" + questionName +
+                               ",questionType=" + questionTypeString +
+                               ",questionClass=" + ( questionClass == IN ? "IN" :
+                                                       "0x" + Log.getHexString( questionClass, 4 )) +
+                               ",recordName=" + recordName +
+                               ",recordType=" + recordTypeString +
+                               ",recordClass=" + ( recordClass == IN ? "IN" :
+                                                       "0x" + Log.getHexString( recordClass, 4 )) +
+                               ",ttl=" + ttl +
+                               ",rDataLength=" + rDataLength );
+       }
+}
+
diff --git a/src/jcifs/netbios/NbtAddress.java b/src/jcifs/netbios/NbtAddress.java
new file mode 100644 (file)
index 0000000..04f0eb2
--- /dev/null
@@ -0,0 +1,632 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.net.SocketException;
+import java.io.IOException;
+import java.util.Hashtable;
+import jcifs.Config;
+
+/**
+ * This class represents a NetBIOS over TCP/IP address. Under normal
+ * conditions, users of jCIFS need not be concerned with this class as
+ * name resolution and session services are handled internally by the smb package.
+ * 
+ * <p> Applications can use the methods <code>getLocalHost</code>,
+ * <code>getAllByName</code>, and
+ * <code>getAllByAddress</code> to create a new NbtAddress instance. This
+ * class is symmetric with {@link java.net.InetAddress}.
+ *
+ * <p><b>About NetBIOS:</b> The NetBIOS name
+ * service is a dynamic distributed service that allows hosts to resolve
+ * names by broadcasting a query, directing queries to a server such as
+ * Samba or WINS. NetBIOS is currently the primary networking layer for
+ * providing name service, datagram service, and session service to the
+ * Microsoft Windows platform. A NetBIOS name can be 15 characters long
+ * and hosts usually registers several names on the network. From a
+ * Windows command prompt you can see
+ * what names a host registers with the nbtstat command.
+ * <p><blockquote><pre>
+ * C:\>nbtstat -a 192.168.1.15
+ * 
+ *        NetBIOS Remote Machine Name Table
+ * 
+ *    Name               Type         Status
+ * ---------------------------------------------
+ * JMORRIS2        <00>  UNIQUE      Registered
+ * BILLING-NY      <00>  GROUP       Registered
+ * JMORRIS2        <03>  UNIQUE      Registered
+ * JMORRIS2        <20>  UNIQUE      Registered
+ * BILLING-NY      <1E>  GROUP       Registered
+ * JMORRIS         <03>  UNIQUE      Registered
+ * 
+ * MAC Address = 00-B0-34-21-FA-3B
+ * </blockquote></pre>
+ * <p> The hostname of this machine is <code>JMORRIS2</code>. It is
+ * a member of the group(a.k.a workgroup and domain) <code>BILLING-NY</code>. To
+ * obtain an {@link java.net.InetAddress} for a host one might do:
+ *
+ * <pre>
+ *   InetAddress addr = NbtAddress.getByName( "jmorris2" ).getInetAddress();
+ * </pre>
+ * <p>From a UNIX platform with Samba installed you can perform similar
+ * diagnostics using the <code>nmblookup</code> utility.
+ *
+ * @author    Michael B. Allen
+ * @see       java.net.InetAddress
+ * @since     jcifs-0.1
+ */ 
+
+public final class NbtAddress {
+
+    Name hostName;
+    int address, nodeType;
+    boolean groupName,
+               isBeingDeleted,
+       isInConflict,
+       isActive,
+       isPermanent,
+       isDataFromNodeStatus;
+    byte[] macAddress;
+
+    private static final byte[] MASTER_BROWSER_BYTES = {
+        (byte)0x01, (byte)0x02, (byte)0x5F, (byte)0x5F, (byte)0x4D, (byte)0x53,
+        (byte)0x42, (byte)0x52, (byte)0x4F, (byte)0x57, (byte)0x53, (byte)0x45,
+        (byte)0x5F, (byte)0x5F, (byte)0x02
+    };
+    private static final byte[] SMBSERVER_BYTES = {
+               (byte)0x2a, (byte)0x53, (byte)0x4d, (byte)0x42, (byte)0x53, (byte)0x45,
+               (byte)0x52, (byte)0x56, (byte)0x45, (byte)0x52, (byte)0x20, (byte)0x20,
+               (byte)0x20, (byte)0x20, (byte)0x20
+    };
+    private static final byte[] ALL_HOSTS_BYTES = {
+        (byte)0x2A, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x00, (byte)0x00
+    };
+
+    // Node Types
+
+/** 
+ * A B node only broadcasts name queries. This is the default if a
+ * nameserver such as WINS or Samba is not specified.
+ */ 
+
+    public static final int B_NODE = 0;
+
+/**
+ * A Point-to-Point node, or P node, unicasts queries to a nameserver
+ * only. Natrually the <code>jcifs.netbios.nameserver</code> property must
+ * be set.
+ */
+
+    public static final int P_NODE = 1;
+
+/** 
+ * Try Broadcast queries first, then try to resolve the name using the
+ * nameserver.
+ */
+
+    public static final int M_NODE = 2;
+
+/** 
+ * A Hybrid node tries to resolve a name using the nameserver first. If that fails use the
+ * broadcast address. This is the default if a nameserver is provided. This
+ * is the behavior of Microsoft Windows machines.
+ */ 
+
+    public static final int H_NODE = 3;
+
+/** 
+ * This is a special name for querying the master browser that serves the
+ * list of hosts found in "Network Neighborhood".
+ */ 
+
+    public static final String MASTER_BROWSER_NAME = new String( MASTER_BROWSER_BYTES );
+
+/**
+ * A special generic name specified when connecting to a host for which a name is not known. Not all servers respond to this name.
+ */
+
+    public static final String SMBSERVER_NAME = new String( SMBSERVER_BYTES );
+
+/** 
+ * This is a special name that means all hosts. If you wish to find all hosts
+ * on a network querying a workgroup group name is the preferred method.
+ */ 
+
+    static final String ALL_HOSTS_NAME = new String( ALL_HOSTS_BYTES );
+
+    NbtAddress( Name hostName, int address, boolean groupName, int nodeType ) {
+        this.hostName = hostName;
+        this.address = address;
+        this.groupName = groupName;
+        this.nodeType = nodeType;
+    }
+    NbtAddress( Name hostName,
+                int address,
+                boolean groupName,
+                int nodeType,
+                boolean isBeingDeleted,
+                boolean isInConflict,
+                boolean isActive,
+                boolean isPermanent,
+                byte[] macAddress ) {
+
+        this.hostName = hostName;
+        this.address = address;
+        this.groupName = groupName;
+        this.nodeType = nodeType;
+        this.isBeingDeleted = isBeingDeleted;
+        this.isInConflict = isInConflict;
+        this.isActive = isActive;
+        this.isPermanent = isPermanent;
+        this.macAddress = macAddress;
+        isDataFromNodeStatus = true;
+    }
+
+/**
+ * Determines if the address is a group address. This is also
+ * known as a workgroup name or group name.
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */
+
+    public boolean isGroupAddress() throws UnknownHostException {
+        checkData();
+        return groupName;
+    }
+
+/** 
+ * Checks the node type of this address.
+ * @return {@link jcifs.netbios.NbtAddress#B_NODE}, {@link jcifs.netbios.NbtAddress#P_NODE}, {@link jcifs.netbios.NbtAddress#M_NODE}, {@link jcifs.netbios.NbtAddress#H_NODE}
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */ 
+
+    public int getNodeType() throws UnknownHostException {
+        checkData();
+        return nodeType;
+    }
+
+/** 
+ * Determines if this address in the process of being deleted.
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */ 
+
+    public boolean isBeingDeleted() throws UnknownHostException {
+        checkNodeStatusData();
+        return isBeingDeleted;
+    }
+
+/** 
+ * Determines if this address in conflict with another address.
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */ 
+
+    public boolean isInConflict() throws UnknownHostException {
+        checkNodeStatusData();
+        return isInConflict;
+    }
+
+/** 
+ * Determines if this address is active.
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */ 
+
+    public boolean isActive() throws UnknownHostException {
+        checkNodeStatusData();
+        return isActive;
+    }
+
+/** 
+ * Determines if this address is set to be permanent.
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */ 
+
+    public boolean isPermanent() throws UnknownHostException {
+        checkNodeStatusData();
+        return isPermanent;
+    }
+
+/** 
+ * Retrieves the MAC address of the remote network interface. Samba returns all zeros.
+ *
+ * @return the MAC address as an array of six bytes
+ * @throws UnknownHostException if the host cannot be resolved to determine the MAC address.
+ */ 
+
+    public byte[] getMacAddress() throws UnknownHostException {
+        checkNodeStatusData();
+        return macAddress;
+    }
+
+/** 
+ * The hostname of this address. If the hostname is null the local machines
+ * IP address is returned.
+ *
+ * @return the text representation of the hostname associated with this address
+ */ 
+
+    public String getHostName() {
+        try {
+                       checkData();
+        } catch( UnknownHostException uhe ) {
+            return getHostAddress();
+        }
+        return hostName.getName();
+    }
+
+       // just for the above methods
+
+    void checkData() throws UnknownHostException {
+        if( hostName.name == ALL_HOSTS_NAME || hostName.name == null ) {
+               getAllByAddress( this );
+        }
+    }
+    void checkNodeStatusData() throws UnknownHostException {
+        if( isDataFromNodeStatus == false ) {
+               getAllByAddress( this );
+        }
+    }
+
+/** 
+ * Returns the raw IP address of this NbtAddress. The result is in network
+ * byte order: the highest order byte of the address is in getAddress()[0].
+ *
+ * @return a four byte array
+ */ 
+
+    public byte[] getAddress() {    
+        byte[] addr = new byte[4];
+
+        addr[0] = (byte)(( address >>> 24 ) & 0xFF );
+        addr[1] = (byte)(( address >>> 16 ) & 0xFF );
+        addr[2] = (byte)(( address >>> 8 ) & 0xFF );
+        addr[3] = (byte)( address & 0xFF );
+        return addr;
+    }
+
+/** 
+ * To convert this address to an <code>InetAddress</code>.
+ *
+ * @return the {@link java.net.InetAddress} representation of this address.
+ */ 
+
+    public InetAddress getInetAddress() throws UnknownHostException {
+        return InetAddress.getByName( getHostAddress() );
+    }
+
+/** 
+ * Returns this IP adress as a {@link java.lang.String} in the form "%d.%d.%d.%d".
+ */ 
+
+    public String getHostAddress() {    
+        return (( address >>> 24 ) & 0xFF ) + "." +
+            (( address >>> 16 ) & 0xFF ) + "." +
+            (( address >>> 8 ) & 0xFF ) + "." +
+            (( address >>> 0 ) & 0xFF );
+    }
+
+/**
+ * Returned the hex code associated with this name(e.g. 0x20 is for the file service)
+ */
+
+       public int getNameType() {
+               return hostName.type;
+       }
+
+/** 
+ * Returns a hashcode for this IP address. The hashcode comes from the IP address
+ * and is not generated from the string representation. So because NetBIOS nodes
+ * can have many names, all names associated with an IP will have the same
+ * hashcode.
+ */ 
+
+    public int hashCode() {
+        return address;
+    }
+
+/** 
+ * Determines if this address is equal two another. Only the IP Addresses
+ * are compared. Similar to the {@link #hashCode} method, the comparison
+ * is based on the integer IP address and not the string representation.
+ */ 
+
+    public boolean equals( NbtAddress nbAddr ) {
+        return ( nbAddr != null ) && ( nbAddr.address == address );
+    }
+
+/** 
+ * Returns the {@link java.lang.String} representaion of this address.
+ */ 
+
+    public String toString() {
+        return hostName.toString() + "/" + getHostAddress();
+    }
+
+/** 
+ * Retrieves the local host address.
+ *
+ * @throws UnknownHostException This is not likely as the IP returned by <code>InetAddress</code> should be available
+ */ 
+
+    public static NbtAddress getLocalHost() throws UnknownHostException {
+        return client.localhost;
+    }
+
+       static final int DEFAULT_CACHE_POLICY = 30;
+    static final int FOREVER = -1;
+
+    static int cachePolicy = Config.getInt( "jcifs.netbios.cachePolicy",
+                                                                                                       DEFAULT_CACHE_POLICY );
+    static Hashtable addressCache = new Hashtable();
+    static NbtAddress unknownAddress;
+    static NbtAddress[] unknown_array;
+
+    static final class CacheEntry {
+               Name hostName;
+        NbtAddress address;
+        long expiration;
+
+        CacheEntry( Name hostName, NbtAddress address, long expiration ) {
+                       this.hostName = hostName;
+            this.address = address;
+            this.expiration = expiration;
+        }
+    }
+
+    static void cacheAddress( Name hostName, NbtAddress addr ) {
+        if( cachePolicy == 0 ) {
+            return;
+        }
+        long expiration = -1;
+        if( cachePolicy != FOREVER ) {
+            expiration = System.currentTimeMillis() + cachePolicy * 1000;
+        }
+        cacheAddress( hostName, addr, expiration );
+    }
+    static void cacheAddress( Name hostName, NbtAddress addr, long expiration ) {
+        if( cachePolicy == 0 ) {
+            return;
+        }
+        synchronized( addressCache ) {
+            CacheEntry entry = (CacheEntry)addressCache.get( hostName );
+            if( entry == null ) {
+                entry = new CacheEntry( hostName, addr, expiration );
+                addressCache.put( hostName, entry );
+            } else {
+                entry.address = addr;
+                entry.expiration = expiration;
+            }
+            Log.printAddressCache( "name service address cache", addressCache );
+        }
+    }
+    static void cacheAddressArray( NbtAddress[] addrs ) {
+        if( cachePolicy == 0 ) {
+            return;
+        }
+        long expiration = -1;
+        if( cachePolicy != FOREVER ) {
+            expiration = System.currentTimeMillis() + cachePolicy * 1000;
+        }
+        synchronized( addressCache ) {
+            for( int i = 0; i < addrs.length; i++ ) {
+                CacheEntry entry = (CacheEntry)addressCache.get( addrs[i].hostName );
+                if( entry == null ) {
+                    entry = new CacheEntry( addrs[i].hostName, addrs[i], expiration );
+                    addressCache.put( addrs[i].hostName, entry );
+                } else {
+                    entry.address = addrs[i];
+                    entry.expiration = expiration;
+                }
+            }
+            Log.printAddressCache( "name service address cache", addressCache );
+        }
+    }
+    static NbtAddress getCachedAddress( Name hostName ) {
+        if( cachePolicy == 0 ) {
+            return null;
+        }
+        synchronized( addressCache ) {
+            CacheEntry entry = (CacheEntry)addressCache.get( hostName );
+            if( entry != null && entry.expiration < System.currentTimeMillis() &&
+                                                                                               entry.expiration >= 0 ) {
+                entry = null;
+            }
+            return entry != null ? entry.address : null;
+        }
+    }
+
+    static NameServiceClient client = new NameServiceClient();
+
+    static {
+        unknownAddress = new NbtAddress( new Name( "0.0.0.0", 0x00, "" ), 0, false, B_NODE );
+        unknown_array = new NbtAddress[1];
+        unknown_array[0] = unknownAddress;
+        addressCache.put( unknownAddress.hostName,
+                                               new CacheEntry( unknownAddress.hostName, unknownAddress, FOREVER ));
+    }
+
+    static NbtAddress doNameQuery( Name name ) throws UnknownHostException {
+
+        NbtAddress addr = getCachedAddress( name );
+
+        if( addr == null ) {
+            try {
+                addr = client.getByName( name );
+            } catch( UnknownHostException uhe ) {
+                addr = unknownAddress;
+            } finally {
+                cacheAddress( name, addr );
+            }
+        }
+        if( addr == unknownAddress ) {
+            throw new UnknownHostException( name.toString() );
+        }
+        return addr;
+    }
+
+/** 
+ * Determines the address of a host given it's host name. The name can be a
+ * machine name like "jcifs.samba.org" or an IP address like "192.168.1.15".
+ *
+ * @param host hostname to resolve
+ * @throws java.net.UnknownHostException if there is an error resolving the name
+ */
+
+    public static NbtAddress getByName( String host )
+                                        throws UnknownHostException {
+        return getByName( host, 0, null );
+    }
+
+/** 
+ * Determines the address of a host given it's host name. NetBIOS
+ * names also have a <code>type</code>. Types(aka Hex Codes)
+ * are used to distiquish the various services on a host. <a
+ * href="../../../nbtcodes.html">Here</a> is
+ * a fairly complete list of NetBIOS hex codes. Scope is not used but is
+ * still functional in other NetBIOS products and so for completeness it has been
+ * implemented. A <code>scope</code> of <code>null</code> or <code>""</code>
+ * signifies no scope.
+ *
+ * @param host the name to resolve
+ * @param type the hex code of the name
+ * @param scope the scope of the name
+ * @throws java.net.UnknownHostException if there is an error resolving the name
+ */
+
+    public static NbtAddress getByName( String host,
+                                        int type,
+                                        String scope )
+                                        throws UnknownHostException {
+
+        if( host == null || host.length() == 0 ) {
+            return getLocalHost();
+        }
+        if( !Character.isDigit( host.charAt(0) )) {
+            return (NbtAddress)doNameQuery( new Name( host, type, scope ));
+        } else {
+            int IP = 0x00;
+            int hitDots = 0;
+            char[] data = host.toCharArray();
+
+            for( int i = 0; i < data.length; i++ ) {
+                char c = data[i];
+                if( c < 48 || c > 57 ) {
+                    return (NbtAddress)doNameQuery( new Name( host, type, scope ));
+                }
+                int b = 0x00;
+                while( c != '.' ) {
+                    if( c < 48 || c > 57 ) {
+                        return (NbtAddress)doNameQuery( new Name( host, type, scope ));
+                    }
+                    b = b * 10 + c - '0';
+
+                    if( ++i >= data.length )
+                        break;
+
+                    c = data[i];
+                }
+                if( b > 0xFF ) {
+                    return (NbtAddress)doNameQuery( new Name( host, type, scope ));
+                }
+                IP = ( IP << 8 ) + b;
+                hitDots++;
+            }
+            if( hitDots != 4 || host.endsWith( "." )) {
+                return (NbtAddress)doNameQuery( new Name( host, type, scope ));
+            }
+            return new NbtAddress( new Name( ALL_HOSTS_NAME, type, scope ),
+                                                                                                       IP, false, B_NODE );
+        }
+    }
+
+/**
+ * Retrieve all addresses of a host by it's address. NetBIOS hosts can
+ * have many names for a given IP address. The name and IP address make the
+ * NetBIOS address. This provides a way to retrieve the other names for a
+ * host with the same IP address.
+ *
+ * @param host hostname to lookup all addresses for
+ * @throws java.net.UnknownHostException if there is an error resolving the name
+ */
+
+
+    public static NbtAddress[] getAllByAddress( String host ) throws UnknownHostException {
+        return getAllByAddress( getByName( host, 0x00, null ));
+    }
+
+
+/**
+ * Retrieve all addresses of a host by it's address. NetBIOS hosts can
+ * have many names for a given IP address. The name and IP address make
+ * the NetBIOS address. This provides a way to retrieve the other names
+ * for a host with the same IP address.  See {@link #getByName}
+ * for a description of <code>type</code>
+ * and <code>scope</code>.
+ *
+ * @param host hostname to lookup all addresses for
+ * @param type the hexcode of the name
+ * @param scope the scope of the name
+ * @throws java.net.UnknownHostException if there is an error resolving the name
+ */
+
+
+    public static NbtAddress[] getAllByAddress( String host,
+                                        int type,
+                                        String scope )
+                                        throws UnknownHostException {
+        return getAllByAddress( getByName( host, type, scope ));
+    }
+
+
+/**
+ * Retrieve all addresses of a host by it's address. NetBIOS hosts can
+ * have many names for a given IP address. The name and IP address make the
+ * NetBIOS address. This provides a way to retrieve the other names for a
+ * host with the same IP address.
+ *
+ * @param addr the address to query
+ * @throws UnknownHostException if address cannot be resolved
+ */
+
+    public static NbtAddress[] getAllByAddress( NbtAddress addr )
+                                                                                               throws UnknownHostException {
+        try {
+            NbtAddress[] addrs = client.getNodeStatus( addr );
+            cacheAddressArray( addrs );
+            return addrs;
+        } catch( UnknownHostException uhe ) {
+            throw new UnknownHostException( "no name with type 0x" +
+                                                       Name.toHexChars( addr.hostName.type ) +
+                                                       ((( addr.hostName.scope == null ) ||
+                                                       ( addr.hostName.scope.length() == 0 )) ?
+                                                       " with no scope" : " with scope " + addr.hostName.scope ) +
+                                                       " for host " + addr.getHostAddress() );
+        }
+    }
+}
+
diff --git a/src/jcifs/netbios/NbtException.java b/src/jcifs/netbios/NbtException.java
new file mode 100644 (file)
index 0000000..c97994f
--- /dev/null
@@ -0,0 +1,103 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import java.io.IOException;
+
+public class NbtException extends IOException {
+
+       // error classes
+       public static final int SUCCESS = 0;
+       public static final int ERR_NAM_SRVC = 0x01;
+       public static final int ERR_SSN_SRVC = 0x02;
+
+       // name service error codes
+       public static final int FMT_ERR = 0x1;
+       public static final int SRV_ERR = 0x2;
+       public static final int IMP_ERR = 0x4;
+       public static final int RFS_ERR = 0x5;
+       public static final int ACT_ERR = 0x6;
+       public static final int CFT_ERR = 0x7;
+
+       // session service error codes
+       public static final int CONNECTION_REFUSED    = -1; 
+       public static final int NOT_LISTENING_CALLED  = 0x80;
+       public static final int NOT_LISTENING_CALLING = 0x81;
+       public static final int CALLED_NOT_PRESENT    = 0x82;
+       public static final int NO_RESOURCES          = 0x83;
+       public static final int UNSPECIFIED           = 0x8F;
+
+       public int errorClass;
+       public int errorCode;
+
+       public static String getErrorString( int errorClass, int errorCode ) {
+               String result = "";
+               switch( errorClass ) {
+                       case SUCCESS:
+                               result += "SUCCESS";
+                               break;
+                       case ERR_NAM_SRVC:
+                               result += "ERR_NAM_SRVC/";
+                               switch( errorCode ) {
+                                       case FMT_ERR:
+                                               result += "FMT_ERR: Format Error";
+                                       default:
+                                               result += "Unknown error code: " + errorCode;
+                               }
+                               break;
+                       case ERR_SSN_SRVC:
+                               result += "ERR_SSN_SRVC/";
+                               switch( errorCode ) {
+                                       case CONNECTION_REFUSED:
+                                               result += "Connection refused";
+                                               break;
+                                       case NOT_LISTENING_CALLED:
+                                               result += "Not listening on called name";
+                                               break;
+                                       case NOT_LISTENING_CALLING:
+                                               result += "Not listening for calling name";
+                                               break;
+                                       case CALLED_NOT_PRESENT:
+                                               result += "Called name not present";
+                                               break;
+                                       case NO_RESOURCES:
+                                               result += "Called name present, but insufficient resources";
+                                               break;
+                                       case UNSPECIFIED:
+                                               result += "Unspecified error";
+                                               break;
+                                       default:
+                                               result += "Unknown error code: " + errorCode;
+                               }
+                               break;
+                       default:
+                               result += "unknown error class: " + errorClass;
+               }
+               return result;
+       }
+
+       public NbtException( int errorClass, int errorCode ) {
+               super( getErrorString( errorClass, errorCode ));
+               this.errorClass = errorClass;
+               this.errorCode = errorCode;
+       }
+       public String toString() {
+               return new String( "errorClass=" + errorClass + ",errorCode=" + errorCode + ",errorString=" + getErrorString( errorClass, errorCode ));
+       }
+}
diff --git a/src/jcifs/netbios/NbtSocket.java b/src/jcifs/netbios/NbtSocket.java
new file mode 100644 (file)
index 0000000..d468032
--- /dev/null
@@ -0,0 +1,121 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import java.net.Socket;
+import java.net.InetAddress;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * This class represents a netbios TCP/IP socket. Under no
+ * conditions will users of jcifs need not be concerned with this class as
+ * netbios services are handled internally to the smb package. It is
+ * only public so the smb package can access it.
+ */
+
+public class NbtSocket extends Socket {
+
+       private static final int SSN_SRVC_PORT = 139;
+       private static final int BUFFER_SIZE = 512;
+
+       NbtAddress address;
+       Name calledName;
+
+       public NbtSocket() {
+               super();
+       }
+       public NbtSocket( NbtAddress address, int port ) throws IOException {
+               this( address, port, null, 0 );
+       }
+       public NbtSocket( NbtAddress address, int port,
+                                                               InetAddress localAddr, int localPort ) throws IOException {
+               this( address, null, port, localAddr, localPort );
+       }
+       public NbtSocket( NbtAddress address, String calledName, int port,
+                                                               InetAddress localAddr, int localPort ) throws IOException {
+               super( address.getInetAddress(), ( port == 0 ? SSN_SRVC_PORT : port ),
+                                                               localAddr, localPort );
+               this.address = address;
+               if( calledName == null ) {
+                       this.calledName = address.hostName;
+               } else {
+                       this.calledName = new Name( calledName, 0x20, null );
+               }
+               connect();
+       }
+
+       public NbtAddress getNbtAddress() {
+               return address;
+       }
+       InputStream getRawInputStream() throws IOException {
+               return super.getInputStream();
+       }
+       OutputStream getRawOutputStream() throws IOException {
+               return super.getOutputStream();
+       }
+       public InputStream getInputStream() throws IOException {
+               return new SocketInputStream( super.getInputStream() );
+       }
+       public OutputStream getOutputStream() throws IOException {
+               return new SocketOutputStream( super.getOutputStream() );
+       }
+       public int getPort() {
+               return super.getPort();
+       }
+       public InetAddress getLocalAddress() {
+               return super.getLocalAddress();
+       }
+       public int getLocalPort() {
+               return super.getLocalPort();
+       }
+       public String toString() {
+               return "NbtSocket[addr=" + address +
+                               ",port=" + super.getPort() +
+                               ",localport=" + super.getLocalPort() + "]";
+       }
+       private void connect() throws IOException {
+               byte[] buffer = new byte[BUFFER_SIZE];
+
+               InputStream in = super.getInputStream();
+               OutputStream out = super.getOutputStream();
+
+               address.checkData();
+               SessionServicePacket ssp0 = new SessionRequestPacket( calledName, NbtAddress.getLocalHost().hostName );
+               out.write( buffer, 0, ssp0.writeWireFormat( buffer, 0 ));
+
+               switch( ssp0.readPacketType( in, buffer, 0 )) {
+                       case SessionServicePacket.POSITIVE_SESSION_RESPONSE:
+                               Log.println( Log.WARNINGS, "session service warning", " session established ok with " + address );
+                               return;
+                       case SessionServicePacket.NEGATIVE_SESSION_RESPONSE:
+                               int errorCode = (int)( in.read() & 0xFF );
+                               throw new NbtException( NbtException.ERR_SSN_SRVC, errorCode );
+                       case -1:
+                               throw new NbtException( NbtException.ERR_SSN_SRVC, NbtException.CONNECTION_REFUSED );
+                       default:
+                               throw new NbtException( NbtException.ERR_SSN_SRVC, 0 );
+               }
+       }
+       public void close() throws IOException {
+               Log.println( Log.WARNINGS, "netbios socket closed", this );
+               super.close();
+       }
+}
diff --git a/src/jcifs/netbios/NodeStatusRequest.java b/src/jcifs/netbios/NodeStatusRequest.java
new file mode 100644 (file)
index 0000000..d8ef2a6
--- /dev/null
@@ -0,0 +1,48 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+class NodeStatusRequest extends NameServicePacket {
+
+       NodeStatusRequest( Name name ) {
+               questionName = name;
+               questionType = NBSTAT;
+       }
+
+       int writeBodyWireFormat( byte[] dst, int dstIndex ) {
+               int tmp = questionName.type;
+               questionName.type = 0x00; // type has to be 0x00 for node status
+               int result = writeQuestionSectionWireFormat( dst, dstIndex );
+               questionName.type = tmp;
+               return result;
+       }
+       int readBodyWireFormat( byte[] src, int srcIndex ) {
+               return 0;
+       }
+       int writeRDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readRDataWireFormat( byte[] src, int srcIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "NodeStatusRequest[" +
+                       super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/netbios/NodeStatusResponse.java b/src/jcifs/netbios/NodeStatusResponse.java
new file mode 100644 (file)
index 0000000..ee96932
--- /dev/null
@@ -0,0 +1,128 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+class NodeStatusResponse extends NameServicePacket {
+
+       NbtAddress queryAddress;
+
+       int numberOfNames;
+       NbtAddress[] addressArray;
+       byte[] macAddress;
+       byte[] stats;
+
+       /* It is a little awkward but prudent to pass the quering address
+        * so that it may be included in the list of results. IOW we do
+        * not want to create a new NbtAddress object for this particular
+        * address from which the query is constructed, we want to populate
+     * the data of the existing address that should be one of several
+        * returned by the node status.
+        */
+
+       NodeStatusResponse( NbtAddress queryAddress ) {
+               this.queryAddress = queryAddress;
+               recordName = new Name( null, 0, null );
+        macAddress = new byte[6];
+       }
+
+       int writeBodyWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readBodyWireFormat( byte[] src, int srcIndex ) {
+               return readResourceRecordWireFormat( src, srcIndex );
+       }
+       int writeRDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readRDataWireFormat( byte[] src, int srcIndex ) {
+               int start = srcIndex;
+               numberOfNames = src[srcIndex] & 0xFF;
+               int namesLength = numberOfNames * 18;
+               int statsLength = rDataLength - namesLength - 1;
+               numberOfNames = src[srcIndex++] & 0xFF;
+               // gotta read the mac first so we can populate addressArray with it
+        System.arraycopy( src, srcIndex + namesLength, macAddress, 0, 6 );
+               srcIndex += readNodeNameArray( src, srcIndex );
+               stats = new byte[statsLength];
+               System.arraycopy( src, srcIndex, stats, 0, statsLength );
+               srcIndex += statsLength;
+               return srcIndex - start;
+       }
+    private int readNodeNameArray( byte[] src, int srcIndex ) {
+               int start = srcIndex;
+
+               addressArray = new NbtAddress[numberOfNames];
+
+        String n;
+        int type;
+        String scope = queryAddress.hostName.scope;
+        boolean groupName;
+        int ownerNodeType;
+        boolean isBeingDeleted;
+        boolean isInConflict;
+        boolean isActive;
+        boolean isPermanent;
+        int j;
+        boolean addrFound = false;
+        for( int i = 0; i < numberOfNames; srcIndex += 18, i++ ) {
+            for( j = srcIndex + 14; src[j] == 0x20; j-- )
+                ;
+            n = new String( src, srcIndex, j - srcIndex + 1 );
+            type             =    src[srcIndex + 15] & 0xFF;
+            groupName        = (( src[srcIndex + 16] & 0x80 ) == 0x80 ) ? true : false;
+            ownerNodeType    =  ( src[srcIndex + 16] & 0x60 ) >> 5;
+            isBeingDeleted   = (( src[srcIndex + 16] & 0x10 ) == 0x10 ) ? true : false;
+            isInConflict     = (( src[srcIndex + 16] & 0x08 ) == 0x08 ) ? true : false;
+            isActive         = (( src[srcIndex + 16] & 0x04 ) == 0x04 ) ? true : false;
+            isPermanent      = (( src[srcIndex + 16] & 0x02 ) == 0x02 ) ? true : false;
+            if( !addrFound && queryAddress.hostName.type == type &&
+                    ( queryAddress.hostName.name == null ||
+                                       queryAddress.hostName.name.equals( NbtAddress.ALL_HOSTS_NAME ) ||
+                                       queryAddress.hostName.name.equalsIgnoreCase( n ))) {
+                queryAddress.hostName.name = n;
+                queryAddress.groupName = groupName;
+                queryAddress.nodeType = ownerNodeType;
+                queryAddress.isBeingDeleted = isBeingDeleted;
+                queryAddress.isInConflict = isInConflict;
+                queryAddress.isActive = isActive;
+                queryAddress.isPermanent = isPermanent;
+                queryAddress.macAddress = macAddress;
+                queryAddress.isDataFromNodeStatus = true;
+                addrFound = true;
+                addressArray[i] = queryAddress;
+            } else {
+                addressArray[i] = new NbtAddress( new Name( n, type, scope ),
+                                        queryAddress.address,
+                                        groupName,
+                                        ownerNodeType,
+                                        isBeingDeleted,
+                                        isInConflict,
+                                        isActive,
+                                        isPermanent,
+                                        macAddress );
+            }
+        }
+        return srcIndex - start;
+    }
+       public String toString() {
+               return new String( "NodeStatusResponse[" +
+                       super.toString() + "]" );
+       }
+}
+
diff --git a/src/jcifs/netbios/SessionRequestPacket.java b/src/jcifs/netbios/SessionRequestPacket.java
new file mode 100644 (file)
index 0000000..e4ef8bb
--- /dev/null
@@ -0,0 +1,55 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class SessionRequestPacket extends SessionServicePacket {
+
+       Name calledName, callingName;
+
+       SessionRequestPacket() {
+               calledName = new Name( null, 0, null );
+               callingName = new Name( null, 0, null );
+       }
+       SessionRequestPacket( Name calledName, Name callingName ) {
+               type = SESSION_REQUEST;
+               this.calledName = calledName;
+               this.callingName = callingName;
+       }
+       int writeTrailerWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+               dstIndex += calledName.writeWireFormat( dst, dstIndex );
+               dstIndex += callingName.writeWireFormat( dst, dstIndex );
+               return dstIndex - start;
+       }
+       int readTrailerWireFormat( InputStream in,
+                                                       byte[] buffer,
+                                                       int bufferIndex )
+                                                       throws IOException {
+               int start = bufferIndex;
+               if( in.read( buffer, bufferIndex, length ) != length ) {
+                       throw new IOException( "invalid session request wire format" );
+               }
+               bufferIndex += calledName.readWireFormat( buffer, bufferIndex );
+               bufferIndex += callingName.readWireFormat( buffer, bufferIndex );
+               return bufferIndex - start;
+       }
+}
diff --git a/src/jcifs/netbios/SessionRetargetResponsePacket.java b/src/jcifs/netbios/SessionRetargetResponsePacket.java
new file mode 100644 (file)
index 0000000..2b55958
--- /dev/null
@@ -0,0 +1,50 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class SessionRetargetResponsePacket extends SessionServicePacket {
+
+       NbtAddress retargetAddress;
+       int retargetPort;
+
+       SessionRetargetResponsePacket() {
+               type = SESSION_RETARGET_RESPONSE;
+               length = 6;
+       }
+
+       int writeTrailerWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readTrailerWireFormat( InputStream in,
+                                                       byte[] buffer,
+                                                       int bufferIndex )
+                                                       throws IOException {
+               if( in.read( buffer, bufferIndex, length ) != length ) {
+                       throw new IOException( "unexpected EOF reading netbios retarget session response" );
+               }
+               int addr = readInt4( buffer, bufferIndex );
+               bufferIndex += 4;
+               retargetAddress = new NbtAddress( null, addr, false, NbtAddress.B_NODE );
+               retargetPort = readInt2( buffer, bufferIndex );
+               return length;
+       }
+}
diff --git a/src/jcifs/netbios/SessionServicePacket.java b/src/jcifs/netbios/SessionServicePacket.java
new file mode 100644 (file)
index 0000000..e88e5d4
--- /dev/null
@@ -0,0 +1,112 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+abstract class SessionServicePacket { 
+
+       // session service packet types 
+       static final int SESSION_MESSAGE = 0x00; 
+       static final int SESSION_REQUEST = 0x81; 
+       static final int POSITIVE_SESSION_RESPONSE = 0x82; 
+       static final int NEGATIVE_SESSION_RESPONSE = 0x83; 
+       static final int SESSION_RETARGET_RESPONSE = 0x84; 
+       static final int SESSION_KEEP_ALIVE = 0x85; 
+
+       static final int MAX_MESSAGE_SIZE = 0x0001FFFF;
+       static final int HEADER_LENGTH = 4;
+
+       static void writeInt2( int val, byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = (byte)(( val >> 8 ) & 0xFF );
+               dst[dstIndex] = (byte)( val & 0xFF );
+       }
+       static void writeInt4( int val, byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = (byte)(( val >> 24 ) & 0xFF );
+               dst[dstIndex++] = (byte)(( val >> 16 ) & 0xFF );
+               dst[dstIndex++] = (byte)(( val >> 8 ) & 0xFF );
+               dst[dstIndex] = (byte)( val & 0xFF );
+       }
+       static int readInt2( byte[] src, int srcIndex ) {
+               return (( src[srcIndex] & 0xFF ) << 8 ) +
+                               ( src[srcIndex + 1] & 0xFF );
+       }
+       static int readInt4( byte[] src, int srcIndex ) {
+               return (( src[srcIndex] & 0xFF ) << 24 ) +
+                               (( src[srcIndex + 1] & 0xFF ) << 16 ) +
+                               (( src[srcIndex + 2] & 0xFF ) << 8 ) +
+                               ( src[srcIndex + 3] & 0xFF );
+       }
+       static int readLength( byte[] src, int srcIndex ) {
+               srcIndex++;
+               return (( src[srcIndex++] & 0x01 ) << 16 ) +
+                               (( src[srcIndex++] & 0xFF ) << 8 ) +
+                               ( src[srcIndex++] & 0xFF );
+       }
+       static int readPacketType( InputStream in,
+                                                                       byte[] buffer,
+                                                                       int bufferIndex )
+                                                                       throws IOException {
+               int n;
+               if(( n = in.read( buffer, bufferIndex, HEADER_LENGTH )) != HEADER_LENGTH ) {
+                       if( n == -1 ) {
+                               return -1;
+                       }
+                       throw new IOException( "unexpected EOF reading netbios session header" );
+               }
+               int t = buffer[bufferIndex] & 0xFF;
+               return t;
+       }
+
+       int type, length;
+
+       int writeWireFormat( byte[] dst, int dstIndex ) {
+               length = writeTrailerWireFormat( dst, dstIndex + HEADER_LENGTH );
+               writeHeaderWireFormat( dst, dstIndex );
+               return HEADER_LENGTH + length;
+       }
+       int readWireFormat( InputStream in, byte[] buffer, int bufferIndex ) throws IOException {
+               readHeaderWireFormat( in, buffer, bufferIndex );
+               return HEADER_LENGTH + readTrailerWireFormat( in, buffer, bufferIndex );
+       }
+       int writeHeaderWireFormat( byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = (byte)type;
+               if( length > 0x0000FFFF ) {
+                       dst[dstIndex] = (byte)0x01;
+               }
+               dstIndex++;
+               writeInt2( length, dst, dstIndex );
+               return HEADER_LENGTH;
+       }
+       int readHeaderWireFormat( InputStream in,
+                                                               byte[] buffer,
+                                                               int bufferIndex )
+                                                               throws IOException {
+               type = buffer[bufferIndex++] & 0xFF;
+               length = (( buffer[bufferIndex] & 0x01 ) << 16 ) + readInt2( buffer, bufferIndex + 1 );
+               return HEADER_LENGTH;
+       }
+
+       abstract int writeTrailerWireFormat( byte[] dst, int dstIndex );
+       abstract int readTrailerWireFormat( InputStream in,
+                                                               byte[] buffer,
+                                                               int bufferIndex )
+                                                               throws IOException;
+} 
diff --git a/src/jcifs/netbios/SocketInputStream.java b/src/jcifs/netbios/SocketInputStream.java
new file mode 100644 (file)
index 0000000..0627c20
--- /dev/null
@@ -0,0 +1,111 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+class SocketInputStream extends InputStream {
+
+       private static final int TMP_BUFFER_SIZE = 256;
+       private InputStream in;
+       private SessionServicePacket ssp;
+       private int tot, bip, n;
+       private byte[] header, tmp;
+
+       SocketInputStream( InputStream in ) {
+               this.in = in;
+               header = new byte[4];
+               tmp = new byte[TMP_BUFFER_SIZE];
+       }
+
+       public synchronized int read() throws IOException {
+               if( read( tmp, 0, 1 ) < 0 ) {
+                       return -1;
+               }
+               return tmp[0] & 0xFF;
+       }
+       public synchronized int read( byte[] b ) throws IOException {
+               return read( b, 0, b.length );
+       }
+
+       /* This method will not return until len bytes have been read
+        * or the stream has been closed.
+        */
+
+       public synchronized int read( byte[] b, int off, int len ) throws IOException {
+               if( len == 0 ) {
+                       return 0;
+               }
+               tot = 0;
+
+               while( true ) {
+                       while( bip > 0 ) {
+                               n = in.read( b, off, Math.min( len, bip ));
+                               if( n == -1 ) {
+                                       return tot > 0 ? tot : -1;
+                               }
+                               tot += n;
+                               off += n;
+                               len -= n;
+                               bip -= n;
+                               if( len == 0 ) {
+                                       return tot;
+                               }
+                       }
+
+                       switch( SessionServicePacket.readPacketType( in, header, 0 )) {
+                               case SessionServicePacket.SESSION_KEEP_ALIVE:
+                                       break;
+                               case SessionServicePacket.SESSION_MESSAGE:
+                                       bip = SessionServicePacket.readLength( header, 0 );
+                                       break;
+                               case -1:
+                                       if( tot > 0 ) {
+                                               return tot;
+                                       }
+                                       return -1;
+                       }
+               }
+       }
+       public synchronized long skip( long numbytes ) throws IOException {
+               if( numbytes <= 0 ) {
+                       return 0;
+               }
+               long n = numbytes;
+               while( n > 0 ) {
+                       int r = read( tmp, 0, (int)Math.min( (long)TMP_BUFFER_SIZE, n ));
+                       if (r < 0) {
+                               break;
+                       }
+                       n -= r;
+               }
+               return numbytes - n;
+       }
+       public int available() throws IOException {
+               if( bip > 0 ) {
+                       return bip;
+               }
+               return in.available();
+       }
+       public void close() throws IOException {
+               in.close();
+       }
+}
+
diff --git a/src/jcifs/netbios/SocketOutputStream.java b/src/jcifs/netbios/SocketOutputStream.java
new file mode 100644 (file)
index 0000000..177bb70
--- /dev/null
@@ -0,0 +1,88 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.netbios;
+
+import java.io.FilterOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import jcifs.util.Log;
+
+class SocketOutputStream extends FilterOutputStream {
+
+       private static int DEFAULT_BUFR_SIZE = 1500;
+
+       private byte[] bufr;
+       private int count, writeSize;
+
+       SocketOutputStream( OutputStream out ) {
+               this( out, DEFAULT_BUFR_SIZE );
+       }
+       SocketOutputStream( OutputStream out, int size ) {
+               super( out );
+               writeSize = jcifs.Config.getInt( "jcifs.netbios.client.writeSize", size );
+               if( writeSize <= 0 ) {
+                       throw new IllegalArgumentException( "buffer size <= 0" );
+               } else if( writeSize > SessionServicePacket.MAX_MESSAGE_SIZE ) {
+                       throw new IllegalArgumentException( "buffer exceeds max netbios message size" );
+               }
+               writeSize += 4;
+               bufr = new byte[writeSize];
+               bufr[0] = (byte)SessionServicePacket.SESSION_MESSAGE;
+               count = 4;
+       }
+
+       public synchronized void write( int b ) throws IOException {
+               if( count >= bufr.length ) {
+                       flush();
+               }
+               bufr[count++] = (byte)b;
+       }
+       public synchronized void write( byte[] b, int off, int len ) throws IOException {
+               if( len >= bufr.length ) {
+                       Log.println( Log.WARNINGS, "session service warning",
+                                                       "write len exceeds pre-allocated buffer size; performance " +
+                                                       "will suffer: len=" + len + ",writeSize=" + writeSize );
+                       flush();
+                       byte[] tmp = bufr;
+                       bufr = new byte[len + 4]; /* at least mantain a permainent fixed size buffer */
+                       System.arraycopy( b, off, bufr, count, len ); /* doah! */
+                       count += len;
+                       flush();
+                       bufr = tmp;
+                       return;
+               }
+               if( len > bufr.length - count ) {
+                       flush();
+               }
+               System.arraycopy( b, off, bufr, count, len );
+               count += len;
+       }
+       public synchronized void flush() throws IOException {
+               if( count == 4 ) {
+                       return;
+               }
+               int n = count - 4;
+               bufr[1] = (byte)(( n & 0x010000 ) == 0x00 ? 0x00 : 0x01 ); 
+               bufr[2] = (byte)(( n >> 8 ) & 0xFF ); 
+               bufr[3] = (byte)( n & 0xFF ); 
+               out.write( bufr, 0, count );
+               out.flush();
+               count = 4;
+       }
+}
diff --git a/src/jcifs/smb/AndXServerMessageBlock.java b/src/jcifs/smb/AndXServerMessageBlock.java
new file mode 100644 (file)
index 0000000..cf6c987
--- /dev/null
@@ -0,0 +1,391 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+abstract class AndXServerMessageBlock extends ServerMessageBlock {
+
+       static final int ANDX_COMMAND_OFFSET  = 1;
+       static final int ANDX_RESERVED_OFFSET = 2;
+       static final int ANDX_OFFSET_OFFSET   = 3;
+
+       ServerMessageBlock andx = null;
+       byte andxCommand        = (byte)0xFF;
+       int andxOffset          = 0;
+
+       AndXServerMessageBlock() {
+       }
+       AndXServerMessageBlock( ServerMessageBlock andx ) {
+               this.andx = andx;
+               if( andx != null ) {
+                       andxCommand = andx.command;
+               }
+       }
+
+       /* The SmbComReadAndXResponse can read from the InputStream
+        * directly by implementing this method. The default
+        * behavior is to arraycopy all bytes into the buffer and call
+        * readBytesWireFormat. The alternative would have been to overload
+        * the readAndXWireFormat method but that would have resulted in
+        * copying a fairly large chunck of code into the subclass.
+        */
+
+       abstract int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException;
+
+       int getBatchLimit( byte command ) {
+               /* the default limit is 0 batched messages before this
+                * one, meaning this message cannot be batched.
+                */
+               return 0;
+       }
+
+       /* 
+        * We overload this method from ServerMessageBlock because
+        * we want writeAndXWireFormat to write the parameterWords
+        * and bytes. This is so we can write batched smbs because
+        * all but the first smb of the chaain do not have a header
+        * and therefore we do not want to writeHeaderWireFormat. We
+        * just recursivly call writeAndXWireFormat.
+        */ 
+
+       int writeWireFormat( byte[] dst, int dstIndex ) {
+               int start = headerStart = dstIndex;
+               dstIndex += writeHeaderWireFormat( dst, dstIndex );
+               dstIndex += writeAndXWireFormat( dst, dstIndex );
+               length = dstIndex - start;
+               return length;
+       }
+
+       /*
+        * We overload this because we want readAndXWireFormat to
+        * read the parameter words and bytes. This is so when
+        * commands are batched together we can recursivly call
+        * readAndXWireFormat without reading the non-existent header.
+        */
+
+       int readWireFormat( InputStream in,
+                                                                       byte[] buffer,
+                                                                       int bufferIndex )
+                                                                       throws IOException {
+               int start = bufferIndex;
+
+               if( in.read( buffer, bufferIndex, HEADER_LENGTH ) != HEADER_LENGTH ) {
+                       throw new IOException( "unexpected EOF reading smb header" );
+               }
+               bufferIndex += readHeaderWireFormat( buffer, bufferIndex );
+               bufferIndex += readAndXWireFormat( in, buffer, bufferIndex );
+
+               length = bufferIndex - start;
+               return length;
+       }
+       int writeAndXWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               wordCount = writeParameterWordsWireFormat( dst,
+                                                                                               start + ANDX_OFFSET_OFFSET + 2 );
+               wordCount += 4; // for command, reserved, and offset
+               dstIndex += wordCount + 1;
+               wordCount /= 2;
+               dst[start] = (byte)( wordCount & 0xFF );
+
+               byteCount = writeBytesWireFormat( dst, dstIndex + 2 );
+               dst[dstIndex++] = (byte)( byteCount & 0xFF );
+               dst[dstIndex++] = (byte)(( byteCount >> 8 ) & 0xFF );
+               dstIndex += byteCount;
+
+               /* Normally, without intervention everything would batch
+                * with everything else. If the below clause evaluates true
+                * the andx command will not be written and therefore the
+                * response will not read a batched command and therefore
+                * the 'received' member of the response object will not
+                * be set to true indicating the send and sendTransaction
+                * methods that the next part should be sent. This is a
+                * very indirect and simple batching control mechanism.
+                */
+
+
+               if( andx == null || useBatching == false ||
+                                                               batchLevel >= getBatchLimit( andx.command )) {
+                       andxCommand = (byte)0xFF;
+                       andx = null;
+
+                       dst[start + ANDX_COMMAND_OFFSET] = (byte)0xFF;
+                       dst[start + ANDX_RESERVED_OFFSET] = (byte)0x00;
+                       dst[start + ANDX_OFFSET_OFFSET] = (byte)0x00;
+                       dst[start + ANDX_OFFSET_OFFSET + 1] = (byte)0x00;
+
+                       // andx not used; return
+                       return dstIndex - start;
+               }
+
+               /* The message provided to batch has a batchLimit that is
+                * higher than the current batchLevel so we will now encode
+                * that chained message. Before doing so we must increment
+                * the batchLevel of the andx message in case it itself is an
+                * andx message and needs to perform the same check as above.
+                */
+
+               andx.batchLevel = batchLevel + 1;
+
+
+               dst[start + ANDX_COMMAND_OFFSET] = andxCommand;
+               dst[start + ANDX_RESERVED_OFFSET] = (byte)0x00;
+               andxOffset = dstIndex - headerStart;
+               writeInt2( andxOffset, dst, start + ANDX_OFFSET_OFFSET );
+
+               andx.useUnicode = useUnicode;
+               if( andx instanceof AndXServerMessageBlock ) {
+
+                       /*
+                        * A word about communicating header info to andx smbs
+                        *
+                        * This is where we recursively invoke the provided andx smb
+                        * object to write it's parameter words and bytes to our outgoing
+                        * array. Incedentally when these andx smbs are created they are not
+                        * necessarily populated with header data because they're not writing
+                        * the header, only their body. But for whatever reason one might wish
+                        * to populate fields if the writeXxx operation needs this header data
+                        * for whatever reason. I copy over the uid here so it appears correct
+                        * in logging output. Logging of andx segments of messages inadvertantly
+                        * print header information because of the way toString always makes a
+                        * super.toString() call(see toString() at the end of all smbs classes).
+                        */
+
+                       andx.uid = uid;
+                       dstIndex += ((AndXServerMessageBlock)andx).writeAndXWireFormat( dst, dstIndex );
+               } else {
+                       // the andx smb is not of type andx so lets just write it here and
+                       // were done.
+                       int andxStart = dstIndex;
+                       andx.wordCount = andx.writeParameterWordsWireFormat( dst, dstIndex );
+                       dstIndex += andx.wordCount + 1;
+                       andx.wordCount /= 2;
+                       dst[andxStart] = (byte)( andx.wordCount & 0xFF );
+       
+                       andx.byteCount = andx.writeBytesWireFormat( dst, dstIndex + 2 );
+                       dst[dstIndex++] = (byte)( andx.byteCount & 0xFF );
+                       dst[dstIndex++] = (byte)(( andx.byteCount >> 8 ) & 0xFF );
+                       dstIndex += andx.byteCount;
+               }
+
+               return dstIndex - start;
+       }
+       int readAndXWireFormat( InputStream in,
+                                                                       byte[] buffer,
+                                                                       int bufferIndex )
+                                                                       throws IOException {
+               int start = bufferIndex;
+
+               /*
+                * read wordCount
+                */
+
+               if(( wordCount = in.read() ) == -1 ) {
+                       throw new IOException( "unexpected EOF reading smb wordCount" );
+               }
+               buffer[bufferIndex++] = (byte)( wordCount & 0xFF );
+
+               /*
+                * read parameterWords
+                */
+
+               if( wordCount != 0 ) {
+                       if( in.read( buffer, bufferIndex, wordCount * 2 ) != ( wordCount * 2 )) {
+                               throw new IOException( "unexpected EOF reading andx parameter words" );
+                       }
+
+                       /*
+                        * these fields are common to all andx commands
+                        * so let's populate them here
+                        */
+       
+                       andxCommand = buffer[bufferIndex];
+                       bufferIndex += 2;
+                       andxOffset = readInt2( buffer, bufferIndex );
+                       bufferIndex += 2;
+       
+                       /*
+                        * no point in calling readParameterWordsWireFormat if there are no more
+                        * parameter words. besides, win98 doesn't return "OptionalSupport" field
+                        */
+       
+                       if( wordCount > 2 ) {
+                               bufferIndex += readParameterWordsWireFormat( buffer, bufferIndex );
+                       }
+               }
+
+               /*
+                * read byteCount
+                */
+
+               if( in.read( buffer, bufferIndex, 2 ) != 2 ) {
+                       throw new IOException( "unexpected EOF reading smb byteCount" );
+               }
+               byteCount = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+       
+               /*
+                * read bytes
+                */
+       
+               if( byteCount != 0 ) {
+                       int n;
+                       n = readBytesDirectWireFormat( in, byteCount );
+                       if( n == 0 ) {
+                               if( in.read( buffer, bufferIndex, byteCount ) != byteCount ) {
+                                       throw new IOException( "unexpected EOF reading andx bytes" );
+                               }
+                               n = readBytesWireFormat( buffer, bufferIndex );
+                       }
+                       if( n != byteCount ) {
+                               Log.println( Log.WARNINGS, "smb andx packet format warning", "byteCount=" +
+                                                               byteCount + " but readBytesWireFormat returned " + n );
+                       }
+                       bufferIndex += byteCount;
+               }
+
+               /*
+                * if there is an andx and it itself is an andx then just recur by
+                * calling this method for it. otherwise just read it's parameter words
+                * and bytes as usual. Note how we can't just call andx.readWireFormat
+                * because there's no header.
+                */
+
+
+               if( errorCode > 0 || andxCommand == (byte)0xFF ) {
+                       andxCommand = (byte)0xFF;
+                       andx = null;
+               } else if( andx == null ) {
+                       andxCommand = (byte)0xFF;
+                       throw new IOException( "no andx command supplied with response" );
+               } else {
+
+                       /*
+                        * This is where we take into account andxOffset
+                        *
+                        * Before we call readAndXWireFormat on the next andx
+                        * part we must take into account the andxOffset. The
+                        * input stream must be positioned at this location. The
+                        * new location is the just read andxOffset(say 68)
+                        * minus the current bufferIndex(say 65). But this packet
+                        * construction/deconstruction technique does not require that
+                        * the bufferIndex begin at 0. The header might be at another
+                        * location(say 4). So we must subtract the current buffer
+                        * index from the real start of the header and substract that
+                        * from the andxOffset(like 68 - ( 65 - 0 ) if headerStart
+                        * were 0 or 68 - ( 69 - 4 ) if the headerStart were 4. We
+                        * also need to communicate to our newly instantiated andx
+                        * smb the headerStart value so that it may perform the same
+                        * calculation as this is a recursive process.
+                        */
+
+                       bufferIndex += in.read( buffer, bufferIndex,
+                                                                       andxOffset - ( bufferIndex - headerStart ));
+
+                       andx.headerStart = headerStart;
+                       andx.command = andxCommand;
+                       andx.errorCode = errorCode;
+                       andx.flags = flags;
+                       andx.flags2 = flags2;
+                       andx.tid = tid;
+                       andx.pid = pid;
+                       andx.uid = uid;
+                       andx.mid = mid;
+                       andx.useUnicode = useUnicode;
+
+                       if( andx instanceof AndXServerMessageBlock ) {
+                               bufferIndex += ((AndXServerMessageBlock)andx).readAndXWireFormat(
+                                                                                               in, buffer, andxOffset - headerStart );
+                       } else {
+
+                               /*
+                                * Just a plain smb. Read it as normal.
+                                */
+
+                               /*
+                                * read wordCount
+                                */
+
+                               if(( andx.wordCount = in.read() ) == -1 ) {
+                                       throw new IOException( "unexpected EOF reading smb wordCount" );
+                               }
+                               buffer[bufferIndex++] = (byte)( andx.wordCount & 0xFF );
+
+                               /*
+                                * read parameterWords
+                                */
+
+                               if( andx.wordCount != 0 ) {
+                                       if( in.read( buffer, bufferIndex, andx.wordCount * 2 ) !=
+                                                                                                                               ( andx.wordCount * 2 )) {
+                                               throw new IOException( "unexpected EOF reading andx parameter words" );
+                                       }
+
+                                       /*
+                                        * no point in calling readParameterWordsWireFormat if there are no more
+                                        * parameter words. besides, win98 doesn't return "OptionalSupport" field
+                                        */
+
+                                       if( andx.wordCount > 2 ) {
+                                               bufferIndex +=
+                                                               andx.readParameterWordsWireFormat( buffer, bufferIndex );
+                                       }
+                               }
+
+                               /*
+                                * read byteCount
+                                */
+
+                               if( in.read( buffer, bufferIndex, 2 ) != 2 ) {
+                                       throw new IOException( "unexpected EOF reading smb byteCount" );
+                               }
+                               andx.byteCount = readInt2( buffer, bufferIndex );
+                               bufferIndex += 2;
+
+                               /*
+                                * read bytes
+                                */
+
+                               if( andx.byteCount != 0 ) {
+                                       if( in.read( buffer, bufferIndex, andx.byteCount ) != andx.byteCount ) {
+                                               throw new IOException( "unexpected EOF reading andx bytes" );
+                                       }
+                                       int n;
+                                       if(( n = andx.readBytesWireFormat( buffer, bufferIndex )) != andx.byteCount ) {
+                                               Log.println( Log.WARNINGS, "smb andx packet format warning",
+                                                                       "byteCount=" + andx.byteCount +
+                                                                       " but readBytesWireFormat returned " + n );
+                                       }
+                                       bufferIndex += andx.byteCount;
+                               }
+                       }
+                       andx.received = true;
+               }
+
+
+               return bufferIndex - start;
+       }
+       public String toString() {
+               return new String( super.toString() +
+                       ",andxCommand=0x" + Log.getHexString( andxCommand, 2 ) +
+                       ",andxOffset=" + andxOffset );
+       }
+}
diff --git a/src/jcifs/smb/Handler.java b/src/jcifs/smb/Handler.java
new file mode 100644 (file)
index 0000000..1a5708b
--- /dev/null
@@ -0,0 +1,44 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.io.IOException;
+
+public class Handler extends URLStreamHandler {
+
+       SmbURL url;
+
+       public URLConnection openConnection( URL u ) throws IOException {
+               return new SmbURLConnection( u, url );
+       }
+       protected void parseURL( URL u, String spec, int start, int limit ) {
+               try {
+                       url = new SmbURL( spec, null, start, limit );
+               } catch( IOException ioe ) {
+                       Log.printStackTrace( "smb URLStreamHandler exception", ioe );
+               }
+               setURL( u, "smb", url.server, url.port, url.canonicalPath, null );
+       }
+       protected String toExternalForm( URL u ) {
+               return url.toString();
+       }
+}
diff --git a/src/jcifs/smb/Info.java b/src/jcifs/smb/Info.java
new file mode 100644 (file)
index 0000000..f800ff7
--- /dev/null
@@ -0,0 +1,25 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+interface Info {
+       int getAttributes();
+       long getLastWriteTime();
+       long getSize();
+}
diff --git a/src/jcifs/smb/Log.java b/src/jcifs/smb/Log.java
new file mode 100644 (file)
index 0000000..ed66505
--- /dev/null
@@ -0,0 +1,59 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+/**
+ * Provides logging methods specific to the smb package. Log class
+ * members are applied to the Log's mask(set as an arithmetic expression
+ * from {@link jcifs.util.Log#setMask(int mask)}) to "flip on" logging of
+ * smb specific information.
+ * <p><blockquote><pre>
+ *     Log.setMask( Log.EXCEPTIONS |
+ *                 jcifs.smb.Log.MESSAGE_DATA );
+ * </pre></blockquote>
+ * <p>
+ * See the {@link jcifs.util.Log} parent class for details about this
+ * logging style.
+ *
+ * @see       jcifs.util.Log
+ * @since     jcifs-0.1
+ */
+
+public class Log extends jcifs.util.Log {
+
+    // supress javadoc constructor summary
+    Log() {}
+
+    public static final int MESSAGE_DATA     = 0x00000100;
+    public static final int TEST1            = 0x00000200;
+    public static final int RESERVED2        = 0x00000400;
+    public static final int RESERVED3        = 0x00000800;
+
+       static void printMessageData( String desc, ServerMessageBlock smb ) {
+               if(( mask & MESSAGE_DATA ) == 0 ) {
+                       return;
+               }
+               try {
+            out.println( desc, smb.toString() + NL );
+        } catch( Exception e ) {
+            Log.printStackTrace( "jcifs.smb.Log.printMessageData()", e );
+        }
+       }
+}
+
diff --git a/src/jcifs/smb/NetServerEnum2.java b/src/jcifs/smb/NetServerEnum2.java
new file mode 100644 (file)
index 0000000..8a722e1
--- /dev/null
@@ -0,0 +1,79 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class NetServerEnum2 extends SmbComTransaction {
+
+       static final int SV_TYPE_ALL         = 0xFFFFFFFF;
+       static final int SV_TYPE_DOMAIN_ENUM = 0x80000000;
+
+       static final byte[] descripters = new String(
+                                       "WrLehDz" + '\0' + "B16BBDz" + '\0' ).getBytes();
+
+       String domain;
+       int serverTypes;
+
+       NetServerEnum2( String domain, int serverTypes ) {
+               this.domain = domain;
+               this.serverTypes = serverTypes;
+               command = SMB_COM_TRANSACTION;
+               name = "\\PIPE\\LANMAN";
+
+               maxParameterCount = 8;
+               maxSetupCount = (byte)0x00;
+               setupCount = 0;
+               timeout = 5000;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               writeInt2( NET_SERVER_ENUM2, dst, dstIndex );
+               dstIndex += 2;
+               System.arraycopy( descripters, 0, dst, dstIndex, descripters.length );
+               dstIndex += descripters.length;
+               writeInt2( 0x0001, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( maxDataCount, dst, dstIndex );
+               dstIndex += 2;
+               writeInt4( serverTypes, dst, dstIndex );
+               dstIndex += 4;
+               dstIndex += writeString( domain.toUpperCase(), dst, dstIndex, false );
+
+               return dstIndex - start;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "NetServerEnum2[" + super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/NetServerEnum2Response.java b/src/jcifs/smb/NetServerEnum2Response.java
new file mode 100644 (file)
index 0000000..0fa9cea
--- /dev/null
@@ -0,0 +1,114 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.util.Log;
+import java.io.InputStream;
+import java.io.IOException;
+
+class NetServerEnum2Response extends SmbComTransactionResponse {
+
+       // transaction response status
+       static final int NERR_Success                = 0;
+       static final int ERROR_MORE_DATA             = 234;
+       static final int NERR_ServerNotStarted       = 2114;
+       static final int NERR_BasicTransactConfig    = 2141;
+
+       class ServerInfo1 {
+               String name;
+               int versionMajor;
+               int versionMinor;
+               int type;
+               String commentOrMasterBrowser;
+
+               public String toString() {
+                       return new String( "ServerInfo1[" +
+                                       "name=" + name +
+                                       ",versionMajor=" + versionMajor +
+                                       ",versionMinor=" + versionMinor +
+                                       ",type=0x" + Log.getHexString( type, 8 ) +
+                                       ",commentOrMasterBrowser=" + commentOrMasterBrowser + "]" );
+               }
+       }
+
+       ServerInfo1[] results;
+       int status, converter, entriesReturned, totalAvailableEntries;
+
+       NetServerEnum2Response() {
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               int start = bufferIndex;
+
+               status = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               converter = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               entriesReturned = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               totalAvailableEntries = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+
+               return bufferIndex - start;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               int start = bufferIndex;
+
+               results = new ServerInfo1[entriesReturned];
+               for( int i = 0; i < entriesReturned; i++ ) {
+                       results[i] = new ServerInfo1();
+                       results[i].name = new String( buffer, bufferIndex,
+                                                       readStringLength( buffer, bufferIndex, 16 ));
+                       bufferIndex += 16;
+                       results[i].versionMajor = (int)( buffer[bufferIndex++] & 0xFF );
+                       results[i].versionMinor = (int)( buffer[bufferIndex++] & 0xFF );
+                       results[i].type = readInt4( buffer, bufferIndex );
+                       bufferIndex += 4;
+                       int off = readInt4( buffer, bufferIndex );
+                       bufferIndex += 4;
+                       off = ( off & 0xFFFF ) - converter;
+                       off = start + off;
+                       results[i].commentOrMasterBrowser = new String( buffer, off,
+                                                       readStringLength( buffer, off, 48 ));
+Log.println( Log.DEBUGGING, "net server enum response entry",  results[i] );
+               }
+
+               return bufferIndex - start;
+       }
+       public String toString() {
+               return new String( "NetServerEnum2Response[" +
+                               super.toString() +
+                               ",status=" + status +
+                               ",converter=" + converter +
+                               ",entriesReturned=" + entriesReturned +
+                               ",totalAvailableEntries=" + totalAvailableEntries + "]" );
+       }
+}
diff --git a/src/jcifs/smb/NetShareEnum.java b/src/jcifs/smb/NetShareEnum.java
new file mode 100644 (file)
index 0000000..01e26ae
--- /dev/null
@@ -0,0 +1,69 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class NetShareEnum extends SmbComTransaction {
+
+       static final byte[] descripters = new String(
+                                       "WrLeh" + '\0' + "B13BWz" + '\0' ).getBytes();
+
+       NetShareEnum() {
+               command = SMB_COM_TRANSACTION;
+               name = new String( "\\PIPE\\LANMAN" );
+               maxParameterCount = 8;
+
+               maxDataCount = 4096;
+               maxSetupCount = (byte)0x00;
+               setupCount = 0;
+               timeout = 5000;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               writeInt2( NET_SHARE_ENUM, dst, dstIndex );
+               dstIndex += 2;
+               System.arraycopy( descripters, 0, dst, dstIndex, descripters.length );
+               dstIndex += descripters.length;
+               writeInt2( 0x0001, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( maxDataCount, dst, dstIndex );
+               dstIndex += 2;
+
+               return dstIndex - start;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "NetShareEnum[" + super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/NetShareEnumResponse.java b/src/jcifs/smb/NetShareEnumResponse.java
new file mode 100644 (file)
index 0000000..0d0d022
--- /dev/null
@@ -0,0 +1,112 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.util.Log;
+import java.io.InputStream;
+import java.io.IOException;
+
+class NetShareEnumResponse extends SmbComTransactionResponse {
+
+       // transaction response status
+       static final int NERR_Success                = 0;
+       static final int ERROR_ACCESS_DENIED         = 5;
+       static final int ERROR_NETWORK_ACCESS_DENIED = 65;
+       static final int ERROR_MORE_DATA             = 234;
+       static final int NERR_ServerNotStarted       = 2114;
+       static final int NERR_BasicTransactConfig    = 2141;
+
+       class ShareInfo1 {
+               String netName;
+               int type;
+               String remark;
+
+               public String toString() {
+                       return new String( "ShareInfo1[" +
+                                       "netName=" + netName +
+                                       ",type=0x" + Log.getHexString( type, 4 ) +
+                                       ",remark=" + remark + "]" );
+               }
+       }
+
+       ShareInfo1[] results;
+       int status, converter, entriesReturned, totalAvailableEntries;
+
+       NetShareEnumResponse() {
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               int start = bufferIndex;
+
+               status = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               converter = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               entriesReturned = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               totalAvailableEntries = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+
+               return bufferIndex - start;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               int start = bufferIndex;
+
+               useUnicode = false;
+
+               results = new ShareInfo1[entriesReturned];
+               for( int i = 0; i < entriesReturned; i++ ) {
+                       results[i] = new ShareInfo1();
+                       results[i].netName = new String( buffer, bufferIndex,
+                                                       readStringLength( buffer, bufferIndex, 13 ));
+                       bufferIndex += 14;
+                       results[i].type = readInt2( buffer, bufferIndex );
+                       bufferIndex += 2;
+                       int off = readInt4( buffer, bufferIndex );
+                       bufferIndex += 4;
+                       off = ( off & 0xFFFF ) - converter;
+                       off = start + off;
+                       results[i].remark = new String( buffer, off,
+                                                       readStringLength( buffer, off, 48 ));
+Log.println( Log.DEBUGGING, "smb warning", results[i] );
+               }
+
+               return bufferIndex - start;
+       }
+       public String toString() {
+               return new String( "NetShareEnumResponse[" +
+                               super.toString() +
+                               ",status=" + status +
+                               ",converter=" + converter +
+                               ",entriesReturned=" + entriesReturned +
+                               ",totalAvailableEntries=" + totalAvailableEntries + "]" );
+       }
+}
diff --git a/src/jcifs/smb/ServerMessageBlock.java b/src/jcifs/smb/ServerMessageBlock.java
new file mode 100644 (file)
index 0000000..0fdac57
--- /dev/null
@@ -0,0 +1,554 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.Config;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.TimeZone;
+import java.util.Calendar;
+import java.util.Date;
+
+abstract class ServerMessageBlock {
+
+       static final int FLAGS_NONE                           = 0x00;
+       static final int FLAGS_LOCK_AND_READ_WRITE_AND_UNLOCK = 0x01;
+       static final int FLAGS_RECEIVE_BUFFER_POSTED          = 0x02;
+       static final int FLAGS_PATH_NAMES_CASELESS            = 0x08;
+       static final int FLAGS_PATH_NAMES_CANONICALIZED       = 0x10;
+       static final int FLAGS_OPLOCK_REQUESTED_OR_GRANTED    = 0x20;
+       static final int FLAGS_NOTIFY_OF_MODIFY_ACTION        = 0x40;
+       static final int FLAGS_RESPONSE                       = 0x80;
+
+       static final int FLAGS2_NONE                          = 0x0000;
+       static final int FLAGS2_LONG_FILENAMES                = 0x0001;
+       static final int FLAGS2_EXTENDED_ATTRIBUTES           = 0x0002;
+       static final int FLAGS2_SECURITY_SIGNATURES           = 0x0004;
+       static final int FLAGS2_EXTENDED_SECURITY_NEGOTIATION = 0x0800;
+       static final int FLAGS2_RESOLVE_PATHS_IN_DFS          = 0x1000;
+       static final int FLAGS2_PERMIT_READ_IF_EXECUTE_PERM   = 0x2000;
+       static final int FLAGS2_STATUS32                      = 0x4000;
+       static final int FLAGS2_UNICODE                       = 0x8000;
+
+       static final int CAP_NONE             = 0x0000;
+       static final int CAP_RAW_MODE         = 0x0001;
+       static final int CAP_MPX_MODE         = 0x0002;
+       static final int CAP_UNICODE          = 0x0004;
+       static final int CAP_LARGE_FILES      = 0x0008;
+       static final int CAP_NT_SMBS          = 0x0010;
+       static final int CAP_RPC_REMOTE_APIS  = 0x0020;
+       static final int CAP_STATUS32         = 0x0040;
+       static final int CAP_LEVEL_II_OPLOCKS = 0x0080;
+       static final int CAP_LOCK_AND_READ    = 0x0100;
+       static final int CAP_NT_FIND          = 0x0200;
+       static final int CAP_DFS              = 0x1000;
+
+       // file attribute encoding
+       static final int ATTR_READONLY   = 0x01;
+       static final int ATTR_HIDDEN     = 0x02;
+       static final int ATTR_SYSTEM     = 0x04;
+       static final int ATTR_VOLUME     = 0x08;
+       static final int ATTR_DIRECTORY  = 0x10;
+       static final int ATTR_ARCHIVE    = 0x20;
+
+       // extended file attribute encoding(others same as above)
+       static final int ATTR_COMPRESSED = 0x800;
+       static final int ATTR_NORMAL     = 0x080;
+       static final int ATTR_TEMPORARY  = 0x100;
+
+       // flags for move and copy
+       static final int FLAGS_TARGET_MUST_BE_FILE         = 0x0001; 
+       static final int FLAGS_TARGET_MUST_BE_DIRECTORY    = 0x0002; 
+       static final int FLAGS_COPY_TARGET_MODE_ASCII      = 0x0004; 
+       static final int FLAGS_COPY_SOURCE_MODE_ASCII      = 0x0008;
+       static final int FLAGS_VERIFY_ALL_WRITES           = 0x0010; 
+       static final int FLAGS_TREE_COPY                   = 0x0020; 
+
+       // open function
+       static final int OPEN_FUNCTION_FAIL_IF_EXISTS      = 0x0000;
+       static final int OPEN_FUNCTION_OVERWRITE_IF_EXISTS = 0x0020;
+
+       static final int PID = (int)( Math.random() * 65536d );
+
+       static final int SECURITY_SHARE = 0x00;
+       static final int SECURITY_USER  = 0x01;
+
+       static final int CMD_OFFSET        = 4;
+       static final int ERROR_CODE_OFFSET = 5;
+       static final int FLAGS_OFFSET      = 9;
+       static final int TID_OFFSET        = 24;
+       static final int HEADER_LENGTH     = 32;
+
+       static final long MILLISECONDS_BETWEEN_1970_AND_1601 = 11644473600000L;
+       static final TimeZone TZ = TimeZone.getDefault();
+
+       static boolean useBatching = Config.getBoolean( "jcifs.smb.client.useBatching", true );
+
+       static final byte[] header = {
+               (byte)0xFF, (byte)'S', (byte)'M', (byte)'B',
+               (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+               (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+               (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+               (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+               (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00
+       };
+
+       static void writeInt2( long val, byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = (byte)((int)(val >>> 0) & 0xFF);
+               dst[dstIndex++] = (byte)((int)(val >>> 8) & 0xFF);
+       }
+       static void writeInt4( long val, byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = (byte)((int)(val >>> 0) & 0xFF);
+               dst[dstIndex++] = (byte)((int)(val >>> 8) & 0xFF);
+               dst[dstIndex++] = (byte)((int)(val >>> 16) & 0xFF);
+               dst[dstIndex++] = (byte)((int)(val >>> 24) & 0xFF);
+       }
+       static int readInt2( byte[] src, int srcIndex ) {
+               return ( src[srcIndex] & 0xFF ) +
+                               (( src[srcIndex + 1] & 0xFF ) << 8 );
+       }
+       static int readInt4( byte[] src, int srcIndex ) {
+               return ( src[srcIndex] & 0xFF ) +
+                               (( src[srcIndex + 1] & 0xFF ) << 8 ) +
+                               (( src[srcIndex + 2] & 0xFF ) << 16 ) +
+                               (( src[srcIndex + 3] & 0xFF ) << 24 );
+       }
+       static long readLong( byte[] src, int srcIndex ) {
+               return (readInt4( src, srcIndex ) & 0xFFFFFFFFL) +
+                       ((long)(readInt4( src, srcIndex + 4 )) << 32);
+       }
+       static void writeLong( long val, byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = (byte)((int)(val >>> 0) & 0xFF);
+               dst[dstIndex++] = (byte)((int)(val >>> 8) & 0xFF);
+               dst[dstIndex++] = (byte)((int)(val >>> 16) & 0xFF);
+               dst[dstIndex++] = (byte)((int)(val >>> 24) & 0xFF);
+               dst[dstIndex++] = (byte)((int)(val >>> 32) & 0xFF);
+               dst[dstIndex++] = (byte)((int)(val >>> 40) & 0xFF);
+               dst[dstIndex++] = (byte)((int)(val >>> 48) & 0xFF);
+               dst[dstIndex++] = (byte)((int)(val >>> 56) & 0xFF);
+       }
+       static long readTime( byte[] src, int srcIndex ) {
+               int low = readInt4( src, srcIndex );
+               int hi = readInt4( src, srcIndex + 4 );
+               long t = ((long)hi << 32 ) | ( (long)low & 0xFFFFFFFFL );
+               t = ( t / 10000L - MILLISECONDS_BETWEEN_1970_AND_1601 );
+
+               synchronized( TZ ) {
+                       if( TZ.inDaylightTime( new Date() )) {
+                               // in dst
+                               if( TZ.inDaylightTime( new Date( t ))) {
+                                       // t also in dst so no correction
+                                       return t;
+                               }
+                               // t not in dst so add 1 hour
+                               return t + 3600000;
+                       } else {
+                               // not in dst
+                               if( TZ.inDaylightTime( new Date( t ))) {
+                                       // t is in dst so subtract 1 hour
+                                       return t - 3600000;
+                               }
+                               // t isn't in dst either
+                               return t;
+                       }
+               }
+       }
+       static long readUTime( byte[] buffer, int bufferIndex ) {
+               return readInt4( buffer, bufferIndex ) * 1000L;
+       }
+
+
+       /*
+        * These are all the smbs supported by this library. This includes requests
+        * and well as their responses for each type however the actuall implementations
+        * of the readXxxWireFormat and writeXxxWireFormat methods may not be in
+        * place. For example at the time of this writing the readXxxWireFormat
+        * for requests and the writeXxxWireFormat for responses are not implemented
+        * and simply return 0. These would need to be completed for a server
+        * implementation.
+        */
+
+       static final byte SMB_COM_CREATE_DIRECTORY   = (byte)0x00;
+       static final byte SMB_COM_DELETE_DIRECTORY   = (byte)0x01;
+       static final byte SMB_COM_CLOSE              = (byte)0x04;
+       static final byte SMB_COM_DELETE             = (byte)0x06;
+       static final byte SMB_COM_RENAME             = (byte)0x07;
+       static final byte SMB_COM_QUERY_INFORMATION  = (byte)0x08;
+       static final byte SMB_COM_CHECK_DIRECTORY    = (byte)0x10;
+       static final byte SMB_COM_TRANSACTION        = (byte)0x25;
+       static final byte SMB_COM_TRANSACTION_SECONDARY = (byte)0x26;
+       static final byte SMB_COM_COPY               = (byte)0x29;
+       static final byte SMB_COM_MOVE               = (byte)0x2A;
+       static final byte SMB_COM_ECHO               = (byte)0x2B;
+       static final byte SMB_COM_OPEN_ANDX          = (byte)0x2D;
+       static final byte SMB_COM_READ_ANDX          = (byte)0x2E;
+       static final byte SMB_COM_WRITE_ANDX         = (byte)0x2F;
+       static final byte SMB_COM_TRANSACTION2       = (byte)0x32;
+       static final byte SMB_COM_FIND_CLOSE2        = (byte)0x34;
+       static final byte SMB_COM_TREE_DISCONNECT    = (byte)0x71;
+       static final byte SMB_COM_NEGOTIATE          = (byte)0x72;
+       static final byte SMB_COM_SESSION_SETUP_ANDX = (byte)0x73;
+       static final byte SMB_COM_LOGOFF_ANDX        = (byte)0x74;
+       static final byte SMB_COM_TREE_CONNECT_ANDX  = (byte)0x75;
+       static final byte SMB_COM_NT_CREATE_ANDX     = (byte)0xA2;
+
+       /*
+        * Some fields specify the offset from the beginning of the header. This
+        * field should be used for calculating that. This would likely be zero
+        * but an implemantation that encorporates the transport header(for
+        * efficiency) might use a different initial bufferIndex. For example,
+        * to eliminate copying data when writing NbtSession data one might
+        * manage that 4 byte header specifically and therefore the initial
+        * bufferIndex, and thus headerStart, would be 4).(NOTE: If one where
+        * looking for a way to improve perfomance this is precisly what you
+        * would want to do as the jcifs.netbios.SocketXxxputStream classes
+        * arraycopy all data read or written into a new buffer shifted over 4!)
+        */
+
+       byte command, flags;
+       int headerStart,
+               length,
+               batchLevel,
+               errorCode,
+               flags2,
+               tid, pid, uid, mid,
+               wordCount, byteCount;
+       boolean useUnicode, received;
+       long responseTimeout = 1;
+
+       ServerMessageBlock() {
+               flags = (byte)( FLAGS_PATH_NAMES_CASELESS | FLAGS_PATH_NAMES_CANONICALIZED );
+               pid = PID;
+               batchLevel = 0;
+       }
+
+       int writeString( String str, byte[] dst, int dstIndex ) {
+               return writeString( str, dst, dstIndex, useUnicode );
+       }
+       int writeString( String str, byte[] dst, int dstIndex, boolean useUnicode ) {
+               int start = dstIndex;
+
+               if( useUnicode ) {
+                       try {
+                               // Unicode requires word alignment
+                               if((( dstIndex - headerStart ) % 2 ) != 0 ) {
+                                       dst[dstIndex++] = (byte)'\0';
+                               }
+                               System.arraycopy( str.getBytes( "UnicodeLittleUnmarked" ), 0,
+                                                                       dst, dstIndex, str.length() * 2 );
+                               dstIndex += str.length() * 2;
+                       } catch( UnsupportedEncodingException uee ) {
+                               Log.printStackTrace( "smb exception", uee );
+                       }
+                       dst[dstIndex++] = (byte)'\0';
+                       dst[dstIndex++] = (byte)'\0';
+               } else {
+                       System.arraycopy( str.getBytes(), 0, dst, dstIndex, str.length() );
+                       dstIndex += str.length();
+                       dst[dstIndex++] = (byte)'\0';
+               }
+
+               return dstIndex - start;
+       }
+       String readString( byte[] src, int srcIndex ) {
+               int len = 0;
+               String str = null;
+               if( useUnicode ) {
+                       // Unicode requires word alignment
+                       if((( srcIndex - headerStart ) % 2 ) != 0 ) {
+                               srcIndex++;
+                       }
+                       while( src[srcIndex + len] != (byte)0x00 ||
+                                                                               src[srcIndex + len + 1] != (byte)0x00 ) {
+                               len += 2;
+                               if( len > 256 ) {
+                                       throw new RuntimeException( "zero termination not found" );
+                               }
+                       }
+                       try {
+                               str = new String( src, srcIndex, len, "UnicodeLittle" );
+                       } catch( UnsupportedEncodingException uee ) {
+                               Log.printStackTrace( "smb exception", uee );
+                       }
+               } else {
+                       while( src[srcIndex + len] != (byte)0x00 ) {
+                               len++;
+                               if( len > 256 ) {
+                                       throw new RuntimeException( "zero termination not found" );
+                               }
+                       }
+                       str = new String( src, srcIndex, len );
+               }
+               return str;
+       }
+       int stringWireLength( String str, int offset ) {
+               int len = str.length() + 1;
+               if( useUnicode ) {
+                       len = str.length() * 2 + 2;
+                       len = ( offset % 2 ) != 0 ? len + 1 : len;
+               }
+               return len;
+       }
+       int readStringLength( byte[] src, int srcIndex, int max ) {
+               int len = 0;
+               while( src[srcIndex + len] != (byte)0x00 ) {
+                       if( len++ > max ) {
+                               throw new RuntimeException( "zero termination not found" );
+                       }
+               }
+               return len;
+       }
+       int writeWireFormat( byte[] dst, int dstIndex ) {
+               int start = headerStart = dstIndex;
+
+               dstIndex += writeHeaderWireFormat( dst, dstIndex );
+               wordCount = writeParameterWordsWireFormat( dst, dstIndex + 1 );
+               dst[dstIndex++] = (byte)(( wordCount / 2 ) & 0xFF );
+               dstIndex += wordCount;
+               wordCount /= 2;
+               byteCount = writeBytesWireFormat( dst, dstIndex + 2 );
+               dst[dstIndex++] = (byte)( byteCount & 0xFF );
+               dst[dstIndex++] = (byte)(( byteCount >> 8 ) & 0xFF );
+               dstIndex += byteCount;
+
+               length = dstIndex - start;
+               return length;
+       }
+       int readWireFormat( InputStream in,
+                                                       byte[] buffer,
+                                                       int bufferIndex )
+                                                       throws IOException {
+
+               int start = headerStart = bufferIndex;
+
+               /*
+                * read header
+                */
+
+               if( in.read( buffer, bufferIndex, HEADER_LENGTH ) != HEADER_LENGTH ) {
+                       throw new IOException( "unexpected EOF reading smb header" );
+               }
+               bufferIndex += readHeaderWireFormat( buffer, bufferIndex );
+
+               /*
+                * read wordCount
+                */
+
+               if(( wordCount = in.read() ) == -1 ) {
+                       throw new IOException( "unexpected EOF reading smb wordCount" );
+               }
+               buffer[bufferIndex++] = (byte)( wordCount & 0xFF );
+
+               /*
+                * read parameter words
+                */
+
+               if( wordCount != 0 ) {
+                       if( in.read( buffer, bufferIndex, wordCount * 2 ) != wordCount * 2 ) {
+                               throw new IOException( "unexpected EOF reading smb parameter words" );
+                       }
+                       int n;
+                       if(( n = readParameterWordsWireFormat( buffer, bufferIndex )) != wordCount * 2 ) {
+                               Log.println( Log.WARNINGS, "smb packet format warning", "wordCount * 2=" +
+                                                               ( wordCount * 2 ) +
+                                                               " but readParameterWordsWireFormat returned " + n );
+                       }
+                       bufferIndex += wordCount * 2;
+               }
+
+               /*
+                * read byteCount
+                */
+
+               if( in.read( buffer, bufferIndex, 2 ) != 2 ) {
+                       throw new IOException( "unexpected EOF reading smb byteCount" );
+               }
+               byteCount = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+
+               /*
+                * read bytes
+                */
+
+               if( byteCount != 0 ) {
+                       if( in.read( buffer, bufferIndex, byteCount ) != byteCount ) {
+                               throw new IOException( "unexpected EOF reading smb" );
+                       }
+                       int n;
+                       if(( n = readBytesWireFormat( buffer, bufferIndex )) != byteCount ) {
+                               Log.println( Log.WARNINGS, "smb packet format warning", "byteCount=" +
+                                                               byteCount + " but readBytesWireFormat returned " + n );
+                       }
+                       // Don't think we can rely on n being correct here. Must use byteCount.
+                       // Last paragraph of section 3.13.3 eludes to this.
+
+                       bufferIndex += byteCount;
+               }
+
+               length = bufferIndex - start;
+               return length;
+       }
+       int writeHeaderWireFormat( byte[] dst, int dstIndex ) {
+               System.arraycopy( header, 0, dst, dstIndex, header.length );
+               dst[dstIndex + CMD_OFFSET] = command;
+               dst[dstIndex + FLAGS_OFFSET] = flags;
+               writeInt2( flags2, dst, dstIndex + FLAGS_OFFSET + 1 );
+               dstIndex += TID_OFFSET;
+               writeInt2( tid, dst, dstIndex );
+               writeInt2( pid, dst, dstIndex + 2 );
+               writeInt2( uid, dst, dstIndex + 4 );
+               writeInt2( mid, dst, dstIndex + 6 );
+               return HEADER_LENGTH;
+       }
+       int readHeaderWireFormat( byte[] buffer, int bufferIndex ) throws IOException {
+               command = buffer[bufferIndex + CMD_OFFSET];
+               errorCode = readInt4( buffer, bufferIndex + ERROR_CODE_OFFSET );
+               flags = buffer[bufferIndex + FLAGS_OFFSET];
+               flags2 = readInt2( buffer, bufferIndex + FLAGS_OFFSET + 1 );
+               tid = readInt2( buffer, bufferIndex + TID_OFFSET );
+               pid = readInt2( buffer, bufferIndex + TID_OFFSET + 2 );
+               uid = readInt2( buffer, bufferIndex + TID_OFFSET + 4 );
+               mid = readInt2( buffer, bufferIndex + TID_OFFSET + 6 );
+               return HEADER_LENGTH;
+       }
+       boolean isResponse() {
+               return ( flags & FLAGS_RESPONSE ) == FLAGS_RESPONSE;
+       }
+
+       /* 
+        * For this packet deconstruction technique to work for
+        * other networking protocols the InputStream may need
+        * to be passed to the readXxxWireFormat methods. This is
+        * actually purer. However, in the case of smb we know the
+        * wordCount and byteCount. And since every subclass of
+        * ServerMessageBlock would have to perform the same read
+        * operation on the input stream, we might as will pull that
+        * common functionality into the superclass and read wordCount
+        * and byteCount worth of data.
+        * 
+        * We will still use the readXxxWireFormat return values to
+        * indicate how many bytes(note: readParameterWordsWireFormat
+        * returns bytes read and not the number of words(but the
+        * wordCount member DOES store the number of words)) we
+        * actually read. Incedentally this is important to the
+        * AndXServerMessageBlock class that needs to potentially
+        * read in another smb's parameter words and bytes based on
+        * information in it's andxCommand, andxOffset, ...etc.
+        */ 
+
+       abstract int writeParameterWordsWireFormat( byte[] dst, int dstIndex );
+       abstract int writeBytesWireFormat( byte[] dst, int dstIndex );
+       abstract int readParameterWordsWireFormat( byte[] buffer,
+                                                                               int bufferIndex )
+                                                                               throws IOException;
+       abstract int readBytesWireFormat( byte[] buffer,
+                                                                               int bufferIndex )
+                                                                               throws IOException;
+
+       public String toString() {
+               String c;
+               switch( command ) {
+                       case SMB_COM_NEGOTIATE:
+                               c = "SMB_COM_NEGOTIATE";
+                               break;
+                       case SMB_COM_SESSION_SETUP_ANDX:
+                               c = "SMB_COM_SESSION_SETUP_ANDX";
+                               break;
+                       case SMB_COM_TREE_CONNECT_ANDX:
+                               c = "SMB_COM_TREE_CONNECT_ANDX";
+                               break;
+                       case SMB_COM_QUERY_INFORMATION:
+                               c = "SMB_COM_QUERY_INFORMATION";
+                               break;
+                       case SMB_COM_CHECK_DIRECTORY:
+                               c = "SMB_COM_CHECK_DIRECTORY";
+                               break;
+                       case SMB_COM_TRANSACTION:
+                               c = "SMB_COM_TRANSACTION";
+                               break;
+                       case SMB_COM_TRANSACTION2:
+                               c = "SMB_COM_TRANSACTION2";
+                               break;
+                       case SMB_COM_TRANSACTION_SECONDARY:
+                               c = "SMB_COM_TRANSACTION_SECONDARY";
+                               break;
+                       case SMB_COM_FIND_CLOSE2:
+                               c = "SMB_COM_FIND_CLOSE2";
+                               break;
+                       case SMB_COM_TREE_DISCONNECT:
+                               c = "SMB_COM_TREE_DISCONNECT";
+                               break;
+                       case SMB_COM_LOGOFF_ANDX:
+                               c = "SMB_COM_LOGOFF_ANDX";
+                               break;
+                       case SMB_COM_ECHO:
+                               c = "SMB_COM_ECHO";
+                               break;
+                       case SMB_COM_MOVE:
+                               c = "SMB_COM_MOVE";
+                               break;
+                       case SMB_COM_RENAME:
+                               c = "SMB_COM_RENAME";
+                               break;
+                       case SMB_COM_COPY:
+                               c = "SMB_COM_COPY";
+                               break;
+                       case SMB_COM_DELETE:
+                               c = "SMB_COM_DELETE";
+                               break;
+                       case SMB_COM_DELETE_DIRECTORY:
+                               c = "SMB_COM_DELETE_DIRECTORY";
+                               break;
+                       case SMB_COM_NT_CREATE_ANDX:
+                               c = "SMB_COM_NT_CREATE_ANDX";
+                               break;
+                       case SMB_COM_OPEN_ANDX:
+                               c = "SMB_COM_OPEN_ANDX";
+                               break;
+                       case SMB_COM_READ_ANDX:
+                               c = "SMB_COM_READ_ANDX";
+                               break;
+                       case SMB_COM_CLOSE:
+                               c = "SMB_COM_CLOSE";
+                               break;
+                       case SMB_COM_WRITE_ANDX:
+                               c = "SMB_COM_WRITE_ANDX";
+                               break;
+                       case SMB_COM_CREATE_DIRECTORY:
+                               c = "SMB_COM_CREATE_DIRECTORY";
+                               break;
+                       default:
+                               c = "UNKNOWN";
+               }
+               return new String(
+                       "command="      + c +
+                       ",received="    + received +
+                       ",errorCode=" + SmbException.getErrorString( errorCode ) +
+                       ",flags=0x"     + Log.getHexString( flags & 0xFF, 4 ) +
+                       ",flags2=0x"    + Log.getHexString( flags2, 4 ) +
+                       ",tid="         + tid +
+                       ",pid="         + pid +
+                       ",uid="         + uid +
+                       ",mid="         + mid +
+                       ",wordCount="   + wordCount +
+                       ",byteCount="   + byteCount );
+       }
+}
diff --git a/src/jcifs/smb/SmbComBlankResponse.java b/src/jcifs/smb/SmbComBlankResponse.java
new file mode 100644 (file)
index 0000000..9093482
--- /dev/null
@@ -0,0 +1,42 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComBlankResponse extends ServerMessageBlock {
+
+       SmbComBlankResponse() {
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComBlankResponse[" +
+                       super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComCheckDirectory.jav b/src/jcifs/smb/SmbComCheckDirectory.jav
new file mode 100644 (file)
index 0000000..a8501b7
--- /dev/null
@@ -0,0 +1,52 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComCheckDirectory extends ServerMessageBlock {
+
+       String directoryPath;
+
+       SmbComCheckDirectory( String directoryPath ) {
+               command = SMB_COM_CHECK_DIRECTORY;
+               this.directoryPath = directoryPath;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               dst[dstIndex++] = (byte)0x04;
+               dstIndex += writeString( directoryPath, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComCheckDirectory[" +
+                       super.toString() +
+                       ",directoryPath=" + directoryPath + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComClose.java b/src/jcifs/smb/SmbComClose.java
new file mode 100644 (file)
index 0000000..163eb79
--- /dev/null
@@ -0,0 +1,54 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.util.Date;
+
+class SmbComClose extends ServerMessageBlock {
+
+       int fid, lastWriteTime;
+
+       SmbComClose( int fid ) {
+               this.fid = fid;
+               command = SMB_COM_CLOSE;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               writeInt2( fid, dst, dstIndex );
+               dstIndex += 2;
+               lastWriteTime = 0xFFFFFFFF;
+               writeInt4( lastWriteTime, dst, dstIndex );
+               return 6;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComClose[" +
+                       super.toString() +
+                       ",fid=" + fid +
+                       ",lastWriteTime=" + ( new Date( lastWriteTime )) + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComCopy.jav b/src/jcifs/smb/SmbComCopy.jav
new file mode 100644 (file)
index 0000000..78c266a
--- /dev/null
@@ -0,0 +1,68 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComCopy extends ServerMessageBlock {
+
+       String sourceFileName;
+       String targetFileName;
+       int tid2;
+       int openFunction;
+       int flags;
+
+       SmbComCopy( String sourceFileName, String targetFileName, int tid2 ) {
+               this.sourceFileName = sourceFileName;
+               this.targetFileName = targetFileName;
+               this.tid2 = tid2 > 0 ? tid2 : -1;
+               command = SMB_COM_COPY;
+               openFunction = OPEN_FUNCTION_FAIL_IF_EXISTS;
+               flags = FLAGS_TARGET_MUST_BE_FILE;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               writeInt2( tid2, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( openFunction, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( flags, dst, dstIndex );
+               return 6;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               dst[dstIndex++] = (byte)0x04;
+               dstIndex += writeString( sourceFileName, dst, dstIndex );
+               dst[dstIndex++] = (byte)0x04;
+               dstIndex += writeString( targetFileName, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComCopy[" +
+                       super.toString() +
+                       ",sourceFileName=" + sourceFileName +
+                       ",targetFileName=" + targetFileName + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComCopyResponse.jav b/src/jcifs/smb/SmbComCopyResponse.jav
new file mode 100644 (file)
index 0000000..8d8595b
--- /dev/null
@@ -0,0 +1,52 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComCopyResponse extends ServerMessageBlock {
+
+       int count;
+       String errorFileName;
+
+       SmbComCopyResponse() {
+               count = 0;
+               errorFileName = "";
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               count = readInt2( buffer, bufferIndex );
+               return 2;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               bufferIndex++;
+               errorFileName = readString( buffer, bufferIndex );
+               return stringWireLength( errorFileName, bufferIndex );
+       }
+       public String toString() {
+               return new String( "SmbComCopyResponse[" +
+                       super.toString() +
+                       ",count=" + count +
+                       ",errorFileName=" + errorFileName + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComCreateDirectory.java b/src/jcifs/smb/SmbComCreateDirectory.java
new file mode 100644 (file)
index 0000000..b4288f2
--- /dev/null
@@ -0,0 +1,52 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComCreateDirectory extends ServerMessageBlock {
+
+       String directoryName;
+
+       SmbComCreateDirectory( String directoryName ) {
+               this.directoryName = directoryName;
+               command = SMB_COM_CREATE_DIRECTORY;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               dst[dstIndex++] = (byte)0x04;
+               dstIndex += writeString( directoryName, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComCreateDirectory[" +
+                       super.toString() +
+                       ",directoryName=" + directoryName + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComDelete.java b/src/jcifs/smb/SmbComDelete.java
new file mode 100644 (file)
index 0000000..0066680
--- /dev/null
@@ -0,0 +1,56 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComDelete extends ServerMessageBlock {
+
+       int searchAttributes;
+       String fileName;
+
+       SmbComDelete( String fileName ) {
+               this.fileName = fileName;
+               command = SMB_COM_DELETE;
+               searchAttributes = ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               writeInt2( searchAttributes, dst, dstIndex );
+               return 2;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               dst[dstIndex++] = (byte)0x04;
+               dstIndex += writeString( fileName, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComDelete[" +
+                       super.toString() +
+                       ",searchAttributes=0x" + Log.getHexString( searchAttributes, 4 ) +
+                       ",fileName=" + fileName + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComDeleteDirectory.java b/src/jcifs/smb/SmbComDeleteDirectory.java
new file mode 100644 (file)
index 0000000..c97eba5
--- /dev/null
@@ -0,0 +1,52 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComDeleteDirectory extends ServerMessageBlock {
+
+       String directoryName;
+
+       SmbComDeleteDirectory( String directoryName ) {
+               this.directoryName = directoryName;
+               command = SMB_COM_DELETE_DIRECTORY;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               dst[dstIndex++] = (byte)0x04;
+               dstIndex += writeString( directoryName, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComDeleteDirectory[" +
+                       super.toString() +
+                       ",directoryName=" + directoryName + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComEcho.jav b/src/jcifs/smb/SmbComEcho.jav
new file mode 100644 (file)
index 0000000..7c7246d
--- /dev/null
@@ -0,0 +1,49 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComEcho extends ServerMessageBlock {
+
+       int echoCount;
+
+       SmbComEcho( int echoCount ) {
+               command = SMB_COM_ECHO;
+               this.echoCount = echoCount;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               writeInt2( echoCount, dst, dstIndex );
+               return 2;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               dst[dstIndex] = (byte)'M';
+               return 1;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComEcho[" +
+                       super.toString() +
+                       ",echoCount=" + echoCount + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComEchoResponse.jav b/src/jcifs/smb/SmbComEchoResponse.jav
new file mode 100644 (file)
index 0000000..a4c4a10
--- /dev/null
@@ -0,0 +1,45 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComEchoResponse extends ServerMessageBlock {
+
+       int sequenceNumber;
+
+       SmbComEchoResponse() {
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               sequenceNumber = readInt2( buffer, bufferIndex );
+               return 2;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 1;
+       }
+       public String toString() {
+               return new String( "SmbComEchoResponse[" +
+                       super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComFindClose2.java b/src/jcifs/smb/SmbComFindClose2.java
new file mode 100644 (file)
index 0000000..5c3ae17
--- /dev/null
@@ -0,0 +1,48 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComFindClose2 extends ServerMessageBlock {
+
+       int sid;
+
+       SmbComFindClose2( int sid ) {
+               this.sid = sid;
+               command = SMB_COM_FIND_CLOSE2;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               writeInt2( sid, dst, dstIndex );
+               return 2;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComFindClose2[" +
+                       super.toString() +
+                       ",sid=" + sid + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComLogoffAndX.java b/src/jcifs/smb/SmbComLogoffAndX.java
new file mode 100644 (file)
index 0000000..cc869b5
--- /dev/null
@@ -0,0 +1,50 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComLogoffAndX extends AndXServerMessageBlock {
+
+       SmbComLogoffAndX( ServerMessageBlock andx ) {
+               super( andx );
+               command = SMB_COM_LOGOFF_ANDX;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComLogoffAndX[" +
+                       super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComMove.jav b/src/jcifs/smb/SmbComMove.jav
new file mode 100644 (file)
index 0000000..b94383f
--- /dev/null
@@ -0,0 +1,73 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComMove extends ServerMessageBlock {
+
+       String oldFileName;
+       String newFileName;
+       int tid2;
+       int openFunction;
+       int flags;
+
+       SmbComMove( String oldFileName, String newFileName, int tid2 ) {
+               command = SMB_COM_MOVE;
+               this.oldFileName = oldFileName;
+               this.newFileName = newFileName;
+               this.tid2 = tid2 == 0 ? -1 : tid2;
+
+               // these will need to be adjusted
+               openFunction = OPEN_FUNCTION_FAIL_IF_EXISTS;
+               flags = FLAGS_TARGET_MUST_BE_FILE;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               writeInt2( tid2, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( openFunction, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( flags, dst, dstIndex );
+               return 6;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               dst[dstIndex++] = (byte)0x04;
+               dstIndex += writeString( oldFileName, dst, dstIndex );
+               dst[dstIndex++] = (byte)0x04;
+               dstIndex += writeString( newFileName, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComMove[" +
+                       super.toString() +
+                       ",oldFileName=" + oldFileName +
+                       ",newFileName=" + newFileName +
+                       ",tid2=" + tid2 +
+                       ",openFunction=" + openFunction +
+                       ",flags=" + flags + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComMoveResponse.jav b/src/jcifs/smb/SmbComMoveResponse.jav
new file mode 100644 (file)
index 0000000..7c267c9
--- /dev/null
@@ -0,0 +1,52 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComMoveResponse extends ServerMessageBlock {
+
+       int count;
+       String errorFileName;
+
+       SmbComMoveResponse() {
+               count = 0;
+               errorFileName = "";
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               count = readInt2( buffer, bufferIndex );
+               return 2;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               bufferIndex++;
+               errorFileName = readString( buffer, bufferIndex );
+               return stringWireLength( errorFileName, bufferIndex );
+       }
+       public String toString() {
+               return new String( "SmbComMoveResponse[" +
+                       super.toString() +
+                       ",count=" + count +
+                       ",errorFileName=" + errorFileName + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComNTCreateAndX.java b/src/jcifs/smb/SmbComNTCreateAndX.java
new file mode 100644 (file)
index 0000000..5128f5d
--- /dev/null
@@ -0,0 +1,212 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComNTCreateAndX extends AndXServerMessageBlock {
+
+       // access mask encoding
+       static final int FILE_READ_DATA        = 0x00000001; // 1
+       static final int FILE_WRITE_DATA       = 0x00000002; // 2
+       static final int FILE_APPEND_DATA      = 0x00000004; // 3
+       static final int FILE_READ_EA          = 0x00000008; // 4
+       static final int FILE_WRITE_EA         = 0x00000010; // 5
+       static final int FILE_EXECUTE          = 0x00000020; // 6
+       static final int FILE_DELETE           = 0x00000040; // 7
+       static final int FILE_READ_ATTRIBUTES  = 0x00000080; // 8
+       static final int FILE_WRITE_ATTRIBUTES = 0x00000100; // 9
+       static final int DELETE                = 0x00010000; // 16
+       static final int READ_CONTROL          = 0x00020000; // 17
+       static final int WRITE_DAC             = 0x00040000; // 18
+       static final int WRITE_OWNER           = 0x00080000; // 19
+       static final int SYNCHRONIZE           = 0x00100000; // 20
+       static final int GENERIC_ALL           = 0x10000000; // 28
+       static final int GENERIC_EXECUTE       = 0x20000000; // 29
+       static final int GENERIC_WRITE         = 0x40000000; // 30
+       static final int GENERIC_READ          = 0x80000000; // 31
+
+       // share access
+       static final int FILE_NO_SHARE     = 0x00;
+       static final int FILE_SHARE_READ   = 0x01;
+       static final int FILE_SHARE_WRITE  = 0x02;
+       static final int FILE_SHARE_DELETE = 0x04;
+
+       // create disposition
+
+       /* Creates a new file or supersedes the existing one
+        */
+
+       static final int FILE_SUPERSEDE    = 0x0;
+
+       /* Open the file or fail if it does not exist
+        * aka OPEN_EXISTING
+        */
+
+       static final int FILE_OPEN         = 0x1;
+
+       /* Create the file or fail if it does not exist
+        * aka CREATE_NEW
+        */
+
+       static final int FILE_CREATE       = 0x2;
+
+       /* Open the file or create it if it does not exist
+        * aka OPEN_ALWAYS
+        */
+
+       static final int FILE_OPEN_IF      = 0x3;
+
+       /* Open the file and overwrite it's contents or fail if it does not exist
+        * aka TRUNCATE_EXISTING
+        */
+
+       static final int FILE_OVERWRITE    = 0x4;
+
+       /* Open the file and overwrite it's contents or create it if it does not exist
+        * aka CREATE_ALWAYS (according to the wire when calling CreateFile)
+        */
+
+       static final int FILE_OVERWRITE_IF = 0x5;
+
+
+       // create options
+       static final int FILE_WRITE_THROUGH           = 0x00000002;
+       static final int FILE_SEQUENTIAL_ONLY         = 0x00000004;
+       static final int FILE_SYNCHRONOUS_IO_ALERT    = 0x00000010;
+       static final int FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020;
+
+       // security flags
+       static final int SECURITY_CONTEXT_TRACKING = 0x01;
+       static final int SECURITY_EFFECTIVE_ONLY   = 0x02;
+
+       String name;
+       int flags,
+               rootDirectoryFid,
+               desiredAccess,
+               extFileAttributes,
+               shareAccess,
+               createDisposition,
+               createOptions,
+               impersonationLevel;
+       long allocationSize;
+       byte securityFlags;
+
+       SmbComNTCreateAndX( String name, int flags, ServerMessageBlock andx ) {
+               super( andx );
+               this.name = name;
+               command = SMB_COM_NT_CREATE_ANDX;
+
+               // desiredAccess
+               desiredAccess = ( flags >>> 16 ) & 0xFFFF;
+               desiredAccess |= FILE_READ_EA | FILE_READ_ATTRIBUTES;
+
+               // extFileAttributes
+               extFileAttributes = ATTR_NORMAL;
+
+               // shareAccess
+               shareAccess = FILE_SHARE_READ;
+
+               // createDisposition
+               if(( flags & SmbFile.O_TRUNC ) == SmbFile.O_TRUNC ) {
+                       // truncate the file
+                       if(( flags & SmbFile.O_CREAT ) == SmbFile.O_CREAT ) {
+                               // create it if necessary
+                               createDisposition = FILE_OVERWRITE_IF;
+                       } else {
+                               createDisposition = FILE_OVERWRITE;
+                       }
+               } else {
+                       // don't truncate the file
+                       if(( flags & SmbFile.O_CREAT ) == SmbFile.O_CREAT ) {
+                               // create it if necessary
+                               if ((flags & SmbFile.O_EXCL ) == SmbFile.O_EXCL ) {
+                                       // fail if already exists
+                                       createDisposition = FILE_CREATE;
+                               } else {
+                                       createDisposition = FILE_OPEN_IF;
+                               }
+                       } else {
+                               createDisposition = FILE_OPEN;
+                       }
+               }
+
+               createOptions = 0x0040; // see netmon
+               impersonationLevel = 0x02; // As seen on NT :~)
+               securityFlags = (byte)0x03; // SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               dst[dstIndex++] = (byte)0x00;
+               // name length without counting null termination
+               writeInt2( ( useUnicode ? name.length() * 2 : name.length() ), dst, dstIndex );
+               dstIndex += 2;
+               writeInt4( flags, dst, dstIndex );
+               dstIndex += 4;
+               writeInt4( rootDirectoryFid, dst, dstIndex );
+               dstIndex += 4;
+               writeInt4( desiredAccess, dst, dstIndex );
+               dstIndex += 4;
+               writeLong( allocationSize, dst, dstIndex );
+               dstIndex += 8;
+               writeInt4( extFileAttributes, dst, dstIndex );
+               dstIndex += 4;
+               writeInt4( shareAccess, dst, dstIndex );
+               dstIndex += 4;
+               writeInt4( createDisposition, dst, dstIndex );
+               dstIndex += 4;
+               writeInt4( createOptions, dst, dstIndex );
+               dstIndex += 4;
+               writeInt4( impersonationLevel, dst, dstIndex );
+               dstIndex += 4;
+               dst[dstIndex++] = securityFlags;
+
+               return dstIndex - start;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return writeString( name, dst, dstIndex );
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComNTCreateAndX[" +
+                       super.toString() +
+                       ",flags=0x" + Log.getHexString( flags, 2 ) +
+                       ",rootDirectoryFid=" + rootDirectoryFid +
+                       ",desiredAccess=0x" + Log.getHexString( desiredAccess, 4 ) +
+                       ",allocationSize=" + allocationSize +
+                       ",extFileAttributes=0x" + Log.getHexString( extFileAttributes, 4 ) +
+                       ",shareAccess=0x" + Log.getHexString( shareAccess, 4 ) +
+                       ",createDisposition=0x" + Log.getHexString( createDisposition, 4 ) +
+                       ",createOptions=0x" + Log.getHexString( createOptions, 8 ) +
+                       ",impersonationLevel=0x" + Log.getHexString( impersonationLevel, 4 ) +
+                       ",securityFlags=0x" + Log.getHexString( securityFlags, 2 ) +
+                       ",name=" + name + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComNTCreateAndXResponse.java b/src/jcifs/smb/SmbComNTCreateAndXResponse.java
new file mode 100644 (file)
index 0000000..e488a04
--- /dev/null
@@ -0,0 +1,105 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.util.Date;
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComNTCreateAndXResponse extends AndXServerMessageBlock {
+
+       static final int EXCLUSIVE_OPLOCK_GRANTED = 1;
+       static final int BATCH_OPLOCK_GRANTED     = 2;
+       static final int LEVEL_II_OPLOCK_GRANTED  = 3;
+
+       byte oplockLevel;
+       int fid,
+               createAction,
+               extFileAttributes,
+               fileType,
+               deviceState;
+       long creationTime,
+               lastAccessTime,
+               lastWriteTime,
+               changeTime,
+               allocationSize,
+               endOfFile;
+       boolean directory;
+
+       SmbComNTCreateAndXResponse() {
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               int start = bufferIndex;
+
+               oplockLevel = buffer[bufferIndex++];
+               fid = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               createAction = readInt4( buffer, bufferIndex );
+               bufferIndex += 4;
+               creationTime = readTime( buffer, bufferIndex );
+               bufferIndex += 8;
+               lastAccessTime = readTime( buffer, bufferIndex );
+               bufferIndex += 8;
+               lastWriteTime = readTime( buffer, bufferIndex );
+               bufferIndex += 8;
+               changeTime = readTime( buffer, bufferIndex );
+               bufferIndex += 8;
+               allocationSize = readLong( buffer, bufferIndex );
+               bufferIndex += 8;
+               endOfFile = readLong( buffer, bufferIndex );
+               bufferIndex += 8;
+               fileType = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               deviceState = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               directory = ( buffer[bufferIndex++] & 0xFF ) > 0;
+
+               return bufferIndex - start;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComNTCreateAndXResponse[" +
+                       super.toString() +
+                       ",oplockLevel=" + oplockLevel +
+                       ",fid=" + fid +
+                       ",createAction=0x" + Log.getHexString( createAction, 4 ) +
+                       ",creationTime=" + new Date( creationTime ) +
+                       ",lastAccessTime=" + new Date( lastAccessTime ) +
+                       ",lastWriteTime=" + new Date( lastWriteTime ) +
+                       ",changeTime=" + new Date( changeTime ) +
+                       ",extFileAttributes=0x" + Log.getHexString( extFileAttributes, 4 ) +
+                       ",allocationSize=" + allocationSize +
+                       ",endOfFile=" + endOfFile +
+                       ",fileType=" + fileType +
+                       ",deviceState=" + deviceState +
+                       ",directory=" + directory + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComNegotiate.java b/src/jcifs/smb/SmbComNegotiate.java
new file mode 100644 (file)
index 0000000..37d25e5
--- /dev/null
@@ -0,0 +1,51 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComNegotiate extends ServerMessageBlock {
+
+       static final byte[] dialects = new String(
+               '\2' + "NT LM 0.12" + '\0' ).getBytes();
+
+       SmbComNegotiate() {
+               command = SMB_COM_NEGOTIATE;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               System.arraycopy( dialects, 0, dst, dstIndex, dialects.length );
+               return dialects.length;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComNegotiate[" +
+                       super.toString() +
+                       ",wordCount="   + wordCount +
+                       ",byteCount="   + dialects.length +
+                       ",dialects=NT LM 0.12]" );
+       }
+}
+
diff --git a/src/jcifs/smb/SmbComNegotiateResponse.java b/src/jcifs/smb/SmbComNegotiateResponse.java
new file mode 100644 (file)
index 0000000..2ce1fb9
--- /dev/null
@@ -0,0 +1,143 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.util.Date;
+import java.io.UnsupportedEncodingException;
+
+class SmbComNegotiateResponse extends ServerMessageBlock {
+
+       int dialectIndex,
+               securityMode,
+               security,
+               maxMpxCount,
+               maxNumberVcs,
+               maxBufferSize,
+               maxRawSize,
+               sessionKey,
+               capabilities,
+               serverTimeZone,
+               encryptionKeyLength;
+       boolean encryptedPasswords,
+               signaturesEnabled,
+               signaturesRequired;
+       long serverTime;
+       byte[] encryptionKey;
+       String oemDomainName;
+
+       SmbComNegotiateResponse() {
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer,
+                                                                       int bufferIndex ) {
+               int start = bufferIndex;
+               dialectIndex        = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               if( dialectIndex > 10 ) {
+                       return bufferIndex - start;
+               }
+               securityMode        = buffer[bufferIndex++] & 0xFF;
+               security            = securityMode & 0x01;
+               encryptedPasswords  = ( securityMode & 0x02 ) == 0x02 ? true : false;
+               signaturesEnabled   = ( securityMode & 0x04 ) == 0x04 ? true : false;
+               signaturesRequired  = ( securityMode & 0x08 ) == 0x08 ? true : false;
+               maxMpxCount         = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               maxNumberVcs        = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               maxBufferSize       = readInt4( buffer, bufferIndex );
+               bufferIndex += 4;
+               maxRawSize          = readInt4( buffer, bufferIndex );
+               bufferIndex += 4;
+               sessionKey          = readInt4( buffer, bufferIndex );
+               bufferIndex += 4;
+               capabilities        = readInt4( buffer, bufferIndex );
+               bufferIndex += 4;
+               serverTime          = readTime( buffer, bufferIndex );
+               bufferIndex += 8;
+               serverTimeZone      = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               encryptionKeyLength = buffer[bufferIndex++] & 0xFF;
+               return bufferIndex - start;
+       }
+       int readBytesWireFormat( byte[] buffer,
+                                                                       int bufferIndex ) {
+               int start = bufferIndex;
+               encryptionKey = new byte[encryptionKeyLength];
+               System.arraycopy( buffer, bufferIndex,
+                                               encryptionKey, 0, encryptionKeyLength );
+               bufferIndex += encryptionKeyLength;
+
+               int len = 0;
+               if(( flags2 & FLAGS2_UNICODE ) == FLAGS2_UNICODE ) {
+                       while( buffer[bufferIndex + len] != (byte)0x00 ||
+                                                                               buffer[bufferIndex + len + 1] != (byte)0x00 ) {
+                               len += 2;
+                               if( len > 256 ) {
+                                       throw new RuntimeException( "zero termination not found" );
+                               }
+                       }
+                       try {
+                               oemDomainName = new String( buffer, bufferIndex, len, "UnicodeLittle" );
+                       } catch( UnsupportedEncodingException uee ) {
+                               Log.printStackTrace( "smb exception", uee );
+                       }
+               } else {
+                       while( buffer[bufferIndex + len] != (byte)0x00 ) {
+                               len++;
+                               if( len > 256 ) {
+                                       throw new RuntimeException( "zero termination not found" );
+                               }
+                       }
+                       oemDomainName = new String( buffer, bufferIndex, len );
+               }
+               bufferIndex += len;
+
+               return bufferIndex - start;
+       }
+       public String toString() {
+               return new String( "SmbComNegotiateResponse[" +
+                       super.toString() +
+                       ",wordCount="           + wordCount +
+                       ",dialectIndex="        + dialectIndex +
+                       ",securityMode=0x"      + Log.getHexString( securityMode, 1 ) +
+                       ",security="            + ( security == SECURITY_SHARE ? "share" : "user" ) +
+                       ",encryptedPasswords="  + encryptedPasswords +
+                       ",maxMpxCount="         + maxMpxCount +
+                       ",maxNumberVcs="        + maxNumberVcs +
+                       ",maxBufferSize="       + maxBufferSize +
+                       ",maxRawSize="          + maxRawSize +
+                       ",sessionKey=0x"        + jcifs.util.Log.getHexString( sessionKey, 8 ) +
+                       ",capabilities=0x"      + jcifs.util.Log.getHexString( capabilities, 8 ) +
+                       ",serverTime="          + new Date( serverTime ) +
+                       ",serverTimeZone="      + serverTimeZone +
+                       ",encryptionKeyLength=" + encryptionKeyLength +
+                       ",byteCount="           + byteCount +
+                       ",encryptionKey=0x"     + Log.getHexString( encryptionKey,
+                                                                                               0,
+                                                                                               encryptionKeyLength * 2 ) +
+                       ",oemDomainName="       + oemDomainName + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComOpenAndX.java b/src/jcifs/smb/SmbComOpenAndX.java
new file mode 100644 (file)
index 0000000..afbe4da
--- /dev/null
@@ -0,0 +1,166 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.Config;
+import java.util.Date;
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComOpenAndX extends AndXServerMessageBlock {
+
+       // flags (not the same as flags constructor argument)
+       static final int FLAGS_RETURN_ADDITIONAL_INFO = 0x01;
+       static final int FLAGS_REQUEST_OPLOCK         = 0x02;
+       static final int FLAGS_REQUEST_BATCH_OPLOCK   = 0x04;
+
+       // Access Mode Encoding for desiredAccess
+       static final int SHARING_COMPATIBILITY           = 0x00;
+       static final int SHARING_DENY_READ_WRITE_EXECUTE = 0x10;
+       static final int SHARING_DENY_WRITE              = 0x20;
+       static final int SHARING_DENY_READ_EXECUTE       = 0x30;
+       static final int SHARING_DENY_NONE               = 0x40;
+
+       static final int DO_NOT_CACHE  = 0x1000; // bit 12
+       static final int WRITE_THROUGH = 0x4000; // bit 14
+
+       static final int OPEN_FN_CREATE = 0x10;
+       static final int OPEN_FN_FAIL_IF_EXISTS = 0x00;
+       static final int OPEN_FN_OPEN = 0x01;
+       static final int OPEN_FN_TRUNC = 0x02;
+
+       static final int BATCH_LIMIT = Config.getInt( "jcifs.smb.client.OpenAndX.ReadAndX", 1 );
+
+       int flags,
+               desiredAccess,
+               searchAttributes,
+               fileAttributes,
+               creationTime,
+               openFunction,
+               allocationSize;
+       String fileName;
+
+       // flags is NOT the same as flags member
+
+       SmbComOpenAndX( String fileName, int flags, ServerMessageBlock andx ) {
+               super( andx );
+               this.fileName = fileName;
+               command = SMB_COM_OPEN_ANDX;
+
+               // flags
+//why!! flags = 0;
+
+               // desiredAccess
+               desiredAccess = ( flags >>> 16 ) & 0x3;
+               if( desiredAccess == 0x3 ) {
+                       desiredAccess = 0x4;
+               }
+               desiredAccess |= SHARING_DENY_NONE;
+               desiredAccess &= ~0x1; // Win98 doesn't like GENERIC_READ ?! -- get Access Denied.
+
+               // searchAttributes
+               searchAttributes = ATTR_DIRECTORY | ATTR_HIDDEN | ATTR_SYSTEM;
+
+               // fileAttributes
+               fileAttributes = 0;
+
+               // openFunction
+               if(( flags & SmbFile.O_TRUNC ) == SmbFile.O_TRUNC ) {
+                       // truncate the file
+                       if(( flags & SmbFile.O_CREAT ) == SmbFile.O_CREAT ) {
+                               // create it if necessary
+                               openFunction = OPEN_FN_TRUNC | OPEN_FN_CREATE;
+                       } else {
+                               openFunction = OPEN_FN_TRUNC;
+                       }
+               } else {
+                       // don't truncate the file
+                       if(( flags & SmbFile.O_CREAT ) == SmbFile.O_CREAT ) {
+                               // create it if necessary
+                               if(( flags & SmbFile.O_EXCL ) == SmbFile.O_EXCL ) {
+                                       // fail if already exists
+                                       openFunction = OPEN_FN_CREATE | OPEN_FN_FAIL_IF_EXISTS;
+                               } else {
+                                       openFunction = OPEN_FN_CREATE | OPEN_FN_OPEN;
+                               }
+                       } else {
+                               openFunction = OPEN_FN_OPEN;
+                       }
+               }
+       }
+
+       int getBatchLimit( byte command ) {
+               return command == SMB_COM_READ_ANDX ? BATCH_LIMIT : 0;
+       }
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               writeInt2( flags, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( desiredAccess, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( searchAttributes, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( fileAttributes, dst, dstIndex );
+               dstIndex += 2;
+               creationTime = 0;
+               writeInt4( creationTime, dst, dstIndex );
+               dstIndex += 4;
+               writeInt2( openFunction, dst, dstIndex );
+               dstIndex += 2;
+               writeInt4( allocationSize, dst, dstIndex );
+               dstIndex += 4;
+               for( int i = 0; i < 8; i++ ) {
+                       dst[dstIndex++] = 0x00;
+               }
+
+               return dstIndex - start;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               if( useUnicode ) {
+                       dst[dstIndex++] = (byte)'\0';
+               }
+               dstIndex += writeString( fileName, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComOpenAndX[" +
+                       super.toString() +
+                       ",flags=0x" + Log.getHexString( flags, 2 ) +
+                       ",desiredAccess=0x" + Log.getHexString( desiredAccess, 4 ) +
+                       ",searchAttributes=0x" + Log.getHexString( searchAttributes, 4 ) +
+                       ",fileAttributes=0x" + Log.getHexString( fileAttributes, 4 ) +
+                       ",creationTime=" + new Date( creationTime ) +
+                       ",openFunction=0x" + Log.getHexString( openFunction, 2 ) +
+                       ",allocationSize=" + allocationSize +
+                       ",fileName=" + fileName + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComOpenAndXResponse.java b/src/jcifs/smb/SmbComOpenAndXResponse.java
new file mode 100644 (file)
index 0000000..1d7e6e5
--- /dev/null
@@ -0,0 +1,88 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComOpenAndXResponse extends AndXServerMessageBlock {
+
+       int fid,
+               fileAttributes,
+               dataSize,
+               grantedAccess,
+               fileType,
+               deviceState,
+               action,
+               serverFid;
+       long lastWriteTime;
+
+       SmbComOpenAndXResponse() {
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               int start = bufferIndex;
+
+               fid = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               fileAttributes = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               lastWriteTime = readUTime( buffer, bufferIndex );
+               bufferIndex += 4;
+               dataSize = readInt4( buffer, bufferIndex );
+               bufferIndex += 4;
+               grantedAccess = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               fileType = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               deviceState = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               action = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               serverFid = readInt4( buffer, bufferIndex );
+               bufferIndex += 6;
+
+               return bufferIndex - start;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComOpenAndXResponse[" +
+                       super.toString() +
+                       ",fid=" + fid +
+                       ",fileAttributes=" + fileAttributes +
+                       ",lastWriteTime=" + lastWriteTime +
+                       ",dataSize=" + dataSize +
+                       ",grantedAccess=" + grantedAccess +
+                       ",fileType=" + fileType +
+                       ",deviceState=" + deviceState +
+                       ",action=" + action +
+                       ",serverFid=" + serverFid + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComQueryInformation.java b/src/jcifs/smb/SmbComQueryInformation.java
new file mode 100644 (file)
index 0000000..b7ac641
--- /dev/null
@@ -0,0 +1,51 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComQueryInformation extends ServerMessageBlock {
+
+       String filename;
+
+       SmbComQueryInformation( String filename ) {
+               this.filename = filename;
+               command = SMB_COM_QUERY_INFORMATION;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+               dst[dstIndex++] = (byte)0x04;
+               dstIndex += writeString( filename, dst, dstIndex );
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComQueryInformation[" +
+                       super.toString() +
+                       ",filename=" + filename + "]" );
+       }
+}
+
diff --git a/src/jcifs/smb/SmbComQueryInformationResponse.java b/src/jcifs/smb/SmbComQueryInformationResponse.java
new file mode 100644 (file)
index 0000000..1feb9ef
--- /dev/null
@@ -0,0 +1,71 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.util.Date;
+
+class SmbComQueryInformationResponse extends ServerMessageBlock implements Info {
+
+       int fileAttributes = 0x0000;
+       long lastWriteTime = 0, serverTimeZoneOffset;
+       int fileSize = 0;
+
+       SmbComQueryInformationResponse( long serverTimeZoneOffset ) {
+               this.serverTimeZoneOffset = serverTimeZoneOffset;
+               command = SMB_COM_QUERY_INFORMATION;
+       }
+
+       public int getAttributes() {
+               return fileAttributes;
+       }
+       public long getLastWriteTime() {
+               return lastWriteTime + serverTimeZoneOffset;
+       }
+       public long getSize() {
+               return fileSize;
+       }
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               if( wordCount == 0 ) {
+                       return 0;
+               }
+               fileAttributes = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               lastWriteTime = readUTime( buffer, bufferIndex );
+               bufferIndex += 4;
+               fileSize = readInt4( buffer, bufferIndex );
+               return 20;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComQueryInformationResponse[" +
+                       super.toString() +
+                       ",fileAttributes=0x" + Log.getHexString( fileAttributes, 4 ) +
+                       ",lastWriteTime=" + new Date( lastWriteTime ) +
+                       ",fileSize=" + fileSize + "]" );
+       }
+}
+
diff --git a/src/jcifs/smb/SmbComReadAndX.java b/src/jcifs/smb/SmbComReadAndX.java
new file mode 100644 (file)
index 0000000..4d184e9
--- /dev/null
@@ -0,0 +1,92 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.Config;
+import java.io.InputStream;
+import java.io.IOException;
+
+class SmbComReadAndX extends AndXServerMessageBlock {
+
+       static final int BATCH_LIMIT = Config.getInt( "jcifs.smb.client.ReadAndX.Close", 1 );
+
+       int fid,
+               offset,
+               maxCount,
+               minCount,
+               openTimeout,
+               remaining;
+
+       SmbComReadAndX( int fid, int offset, int maxCount, ServerMessageBlock andx ) {
+               super( andx );
+               this.fid = fid;
+               this.offset = offset;
+               this.maxCount = minCount = maxCount;
+               command = SMB_COM_READ_ANDX;
+               openTimeout = 0xFFFFFFFF;
+       }
+
+       int getBatchLimit( byte command ) {
+               return command == SMB_COM_CLOSE ? BATCH_LIMIT : 0;
+       }
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               writeInt2( fid, dst, dstIndex );
+               dstIndex += 2;
+               writeInt4( offset, dst, dstIndex );
+               dstIndex += 4;
+               writeInt2( maxCount, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( minCount, dst, dstIndex );
+               dstIndex += 2;
+               writeInt4( openTimeout, dst, dstIndex );
+               dstIndex += 4;
+               writeInt2( remaining, dst, dstIndex );
+               dstIndex += 2;
+               writeInt4( 0, dst, dstIndex );
+               dstIndex += 4;
+
+               return dstIndex - start;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComReadAndX[" +
+                       super.toString() +
+                       ",fid=" + fid +
+                       ",offset=" + offset +
+                       ",maxCount=" + maxCount +
+                       ",minCount=" + minCount +
+                       ",openTimeout=" + openTimeout +
+                       ",remaining=" + remaining +
+                       ",offset=" + maxCount +
+                        "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComReadAndXResponse.java b/src/jcifs/smb/SmbComReadAndXResponse.java
new file mode 100644 (file)
index 0000000..560b4fb
--- /dev/null
@@ -0,0 +1,73 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComReadAndXResponse extends AndXServerMessageBlock {
+
+       byte[] b;
+       int dataCompactionMode,
+               dataLength,
+               dataOffset,
+               off;
+
+       SmbComReadAndXResponse( byte[] b, int off ) {
+               this.b = b;
+               this.off = off;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               int start = bufferIndex;
+
+               bufferIndex += 2; // reserved
+               dataCompactionMode = readInt2( buffer, bufferIndex );
+               bufferIndex += 4; // 2 reserved
+               dataLength = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               dataOffset = readInt2( buffer, bufferIndex );
+               bufferIndex += 12; // 10 reserved
+
+               return bufferIndex - start;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+
+               int pad = dataOffset - ( HEADER_LENGTH + 3 + wordCount * 2 );
+               in.skip( pad );
+               in.read( b, off, dataLength );
+               return pad + dataLength;
+       }
+       public String toString() {
+               return new String( "SmbComReadAndXResponse[" +
+                       super.toString() +
+                       ",dataCompactionMode=" + dataCompactionMode +
+                       ",dataLength=" + dataLength +
+                       ",dataOffset=" + dataOffset + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComRename.java b/src/jcifs/smb/SmbComRename.java
new file mode 100644 (file)
index 0000000..bffbe07
--- /dev/null
@@ -0,0 +1,64 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComRename extends ServerMessageBlock {
+
+       int searchAttributes;
+       String oldFileName;
+       String newFileName;
+
+       SmbComRename( String oldFileName, String newFileName ) {
+               command = SMB_COM_RENAME;
+               this.oldFileName = oldFileName;
+               this.newFileName = newFileName;
+               searchAttributes = ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               writeInt2( searchAttributes, dst, dstIndex );
+               return 2;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               dst[dstIndex++] = (byte)0x04;
+               dstIndex += writeString( oldFileName, dst, dstIndex );
+               dst[dstIndex++] = (byte)0x04;
+               if( useUnicode ) {
+                       dst[dstIndex++] = (byte)'\0';
+               }
+               dstIndex += writeString( newFileName, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComRename[" +
+                       super.toString() +
+                       ",searchAttributes=0x" + Log.getHexString( searchAttributes, 4 ) +
+                       ",oldFileName=" + oldFileName +
+                       ",newFileName=" + newFileName + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComSessionSetupAndX.java b/src/jcifs/smb/SmbComSessionSetupAndX.java
new file mode 100644 (file)
index 0000000..6d54646
--- /dev/null
@@ -0,0 +1,158 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.Config;
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComSessionSetupAndX extends AndXServerMessageBlock {
+
+       static final int BATCH_LIMIT =
+                       Config.getInt( "jcifs.smb.client.SessionSetupAndX.TreeConnectAndX", 1 );
+
+       byte[] accountPassword, unicodePassword;
+       int passwordLength, unicodePasswordLength;
+       int negotiatedMaxBufferSize,
+               negotiatedMaxMpxCount,
+               vcNumber,
+               sessionKey;
+       String accountName,
+               primaryDomain,
+               nativeOs,
+               nativeLanMan;
+
+       SmbSession session;
+
+       SmbComSessionSetupAndX( SmbSession session, ServerMessageBlock andx ) {
+               super( andx );
+               command = SMB_COM_SESSION_SETUP_ANDX;
+               this.session = session;
+       }
+
+       int getBatchLimit( byte command ) {
+               return command == SMB_COM_TREE_CONNECT_ANDX ? BATCH_LIMIT : 0;
+       }
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               if( session.transport.server.security == SECURITY_USER &&
+                                                                                                       session.password.length() != 0 ) {
+                       if( session.transport.server.encryptedPasswords ) {
+                               // encrypted
+                               accountPassword = SmbSession.getPreNTLMResponse( session.password,
+                                                                                       session.transport.server.encryptionKey );
+                               unicodePassword = SmbSession.getNTLMResponse( session.password,
+                                                                                       session.transport.server.encryptionKey );
+                               passwordLength = unicodePasswordLength = 24;
+                       } else {
+                               // plain text
+                               throw new RuntimeException( "plain text passwords not implemented" );
+                       }
+               } else {
+                       // no password in session setup
+                       passwordLength = unicodePasswordLength = 0;
+               }
+
+               negotiatedMaxBufferSize = session.transport.negotiatedMaxBufferSize;
+               negotiatedMaxMpxCount = session.transport.negotiatedMaxMpxCount;
+               vcNumber = session.transport.client.vcNumber;
+               sessionKey = session.transport.client.sessionKey;
+
+               writeInt2( negotiatedMaxBufferSize, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( negotiatedMaxMpxCount, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( vcNumber, dst, dstIndex );
+               dstIndex += 2;
+               writeInt4( sessionKey, dst, dstIndex );
+               dstIndex += 4;
+               writeInt2( passwordLength, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( unicodePasswordLength, dst, dstIndex );
+               dstIndex += 2;
+               dst[dstIndex++] = (byte)0x00;
+               dst[dstIndex++] = (byte)0x00;
+               dst[dstIndex++] = (byte)0x00;
+               dst[dstIndex++] = (byte)0x00;
+               writeInt4( session.transport.client.capabilities, dst, dstIndex );
+               dstIndex += 4;
+
+               return dstIndex - start;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               accountName = session.username;
+               primaryDomain = session.domain;
+               nativeOs = session.transport.client.nativeOs;
+               nativeLanMan = session.transport.client.nativeLanMan;
+
+               if( session.transport.server.security == SECURITY_USER &&
+                                                                                                       session.password.length() != 0 ) {
+                       System.arraycopy( accountPassword, 0, dst, dstIndex, passwordLength );
+                       dstIndex += passwordLength;
+                       System.arraycopy( unicodePassword, 0, dst, dstIndex, unicodePasswordLength );
+                       dstIndex += unicodePasswordLength;
+               }
+               if( useUnicode ) {
+                       // at least NT 4 observed needing this only with unicode
+                       dst[dstIndex++] = (byte)'\0';
+               }
+
+               dstIndex += writeString( accountName, dst, dstIndex );
+               dstIndex += writeString( primaryDomain, dst, dstIndex );
+               dstIndex += writeString( nativeOs, dst, dstIndex );
+/*
+               // at least NT 4 observed with 2 zero bytes here
+               dst[dstIndex++] = (byte)0x00;
+               dst[dstIndex++] = (byte)0x00;
+This still isn't quite right.
+*/
+               dstIndex += writeString( nativeLanMan, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               String result = new String( "SmbComSessionSetupAndX[" +
+                       super.toString() +
+                       ",maxBufferSize=" + negotiatedMaxBufferSize +
+                       ",maxMpxCount=" + negotiatedMaxMpxCount +
+                       ",vcNumber=" + vcNumber +
+                       ",sessionKey=" + sessionKey +
+                       ",passwordLength=" + passwordLength +
+                       ",unicodePasswordLength=" + unicodePasswordLength +
+                       ",capabilities=" + session.transport.client.capabilities +
+                       ",accountPassword=" + accountPassword +
+                       ",accountName=" + accountName +
+                       ",primaryDomain=" + primaryDomain +
+                       ",nativeOs=" + nativeOs +
+                       ",nativeLanMan=" + nativeLanMan + "]" );
+               return result;
+       }
+}
diff --git a/src/jcifs/smb/SmbComSessionSetupAndXResponse.java b/src/jcifs/smb/SmbComSessionSetupAndXResponse.java
new file mode 100644 (file)
index 0000000..9695e6b
--- /dev/null
@@ -0,0 +1,70 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComSessionSetupAndXResponse extends AndXServerMessageBlock {
+
+       boolean isLoggedInAsGuest;
+       String nativeOs = "";
+       String nativeLanMan = "";
+       String primaryDomain = "";
+
+       SmbComSessionSetupAndXResponse( ServerMessageBlock andx ) {
+               super( andx );
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               isLoggedInAsGuest = ( buffer[bufferIndex] & 0x01 ) == 0x01 ? true : false;
+               return 2;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               int start = bufferIndex;
+
+               nativeOs = readString( buffer, bufferIndex );
+               bufferIndex += stringWireLength( nativeOs, bufferIndex );
+               nativeLanMan = readString( buffer, bufferIndex );
+               bufferIndex += stringWireLength( nativeLanMan, bufferIndex );
+               primaryDomain = readString( buffer, bufferIndex );
+               bufferIndex += stringWireLength( primaryDomain, bufferIndex );
+
+               return bufferIndex - start;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               String result = new String( "SmbComSessionSetupAndXResponse[" +
+                       super.toString() +
+                       ",isLoggedInAsGuest=" + isLoggedInAsGuest +
+                       ",nativeOs=" + nativeOs +
+                       ",nativeLanMan=" + nativeLanMan +
+                       ",primaryDomain=" + primaryDomain + "]" );
+               return result;
+       }
+}
+
diff --git a/src/jcifs/smb/SmbComTransaction.java b/src/jcifs/smb/SmbComTransaction.java
new file mode 100644 (file)
index 0000000..d0f84f9
--- /dev/null
@@ -0,0 +1,253 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.util.Enumeration;
+import jcifs.Config;
+
+abstract class SmbComTransaction extends ServerMessageBlock implements Enumeration {
+
+       static final byte TRANS2_FIND_FIRST2            = (byte)0x01;
+       static final byte TRANS2_FIND_NEXT2             = (byte)0x02;
+       static final byte TRANS2_QUERY_FS_INFORMATION   = (byte)0x03;
+       static final byte TRANS2_QUERY_PATH_INFORMATION = (byte)0x05;
+
+       static final int NET_SHARE_ENUM   = 0x0000;
+       static final int NET_SERVER_ENUM2 = 0x0068;
+
+       static final byte TRANS_WAIT_NAMED_PIPE     = (byte)0x53;
+       static final byte TRANS_CALL_NAMED_PIPE     = (byte)0x54;
+       static final byte TRANS_TRANSACT_NAMED_PIPE = (byte)0x26;
+
+       // relative to headerStart
+       static final int PRIMARY_SETUP_OFFSET        = 61;
+       static final int SECONDARY_PARAMETER_OFFSET  = 51;
+
+       static final int DISCONNECT_TID      = 0x01;
+       static final int ONE_WAY_TRANSACTION = 0x02;
+
+       static final int PADDING_SIZE = 2;
+
+       static final int DEFAULT_TRANSACTION_BUF_SIZE = 0xFFFF;
+
+       int totalParameterCount;
+       int totalDataCount;
+       int maxParameterCount;
+       int maxDataCount;
+       byte maxSetupCount;
+       int flags = 0x00;
+       int timeout = 0;
+       int parameterCount;
+       int parameterOffset;
+       int parameterDisplacement;
+       int dataCount;
+       int dataOffset;
+       int dataDisplacement;
+       int fid;
+       int setupCount = 1;
+       byte subCommand;
+       String name = "";
+       int pad = 0;
+       int pad1 = 0;
+       boolean hasMore = true;
+       boolean isPrimary = true;
+       int maxBufferSize; // set in SmbTransport.sendTransaction() before nextElement called
+
+       byte[] buf = new byte[DEFAULT_TRANSACTION_BUF_SIZE]; // yuck
+       int bufParameterOffset;
+       int bufDataOffset;
+
+       SmbComTransaction() {
+               maxParameterCount = 1024;
+               // subtract 512 just to be safe
+               maxDataCount = Config.getInt( "jcifs.smb.client.transaction_buf_size",
+                                                               SmbComTransactionResponse.DEFAULT_TRANSACTION_BUF_SIZE ) - 512;
+       }
+
+       public boolean hasMoreElements() {
+               return hasMore;
+       }
+       public Object nextElement() {
+               if( isPrimary ) {
+                       isPrimary = false;
+
+                       parameterOffset = PRIMARY_SETUP_OFFSET + ( setupCount * 2 ) + 2;
+                       if( command == SMB_COM_TRANSACTION && isResponse() == false ) {
+                               parameterOffset += stringWireLength( name, parameterOffset );
+                       }
+                       pad = parameterOffset % PADDING_SIZE;
+                       pad = pad == 0 ? 0 : PADDING_SIZE - pad;
+                       parameterOffset += pad;
+
+                       totalParameterCount = writeParametersWireFormat( buf, bufParameterOffset );
+                       bufDataOffset = totalParameterCount; // data comes right after data
+
+                       int available = maxBufferSize - parameterOffset;
+                       parameterCount = Math.min( totalParameterCount, available );
+                       available -= parameterCount;
+
+                       dataOffset = parameterOffset + parameterCount;
+                       pad1 = dataOffset % PADDING_SIZE;
+                       pad1 = pad1 == 0 ? 0 : PADDING_SIZE - pad1;
+                       dataOffset += pad1;
+
+                       totalDataCount = writeDataWireFormat( buf, bufDataOffset );
+
+                       dataCount = Math.min( totalDataCount, available );
+               } else {
+                       command = SMB_COM_TRANSACTION_SECONDARY;
+                       // totalParameterCount and totalDataCount are set ok from primary
+
+                       parameterOffset = SECONDARY_PARAMETER_OFFSET;
+                       if(( totalParameterCount - parameterDisplacement ) > 0 ) {
+                               pad = parameterOffset % PADDING_SIZE;
+                               pad = pad == 0 ? 0 : PADDING_SIZE - pad;
+                               parameterOffset += pad;
+                       }
+
+                       // caclulate parameterDisplacement before calculating new parameterCount
+                       parameterDisplacement += parameterCount;
+
+                       int available = maxBufferSize - parameterOffset - pad;
+                       parameterCount = Math.min( totalParameterCount - parameterDisplacement, available);
+                       available -= parameterCount;
+
+                       dataOffset = parameterOffset + parameterCount;
+                       pad1 = dataOffset % PADDING_SIZE;
+                       pad1 = pad1 == 0 ? 0 : PADDING_SIZE - pad1;
+                       dataOffset += pad1;
+
+                       dataDisplacement += dataCount;
+
+                       available -= pad1;
+                       dataCount = Math.min( totalDataCount - dataDisplacement, available );
+               }
+               if(( parameterDisplacement + parameterCount ) >= totalParameterCount &&
+                                       ( dataDisplacement + dataCount ) >= totalDataCount ) {
+                       hasMore = false;
+               }
+               return this;
+       }
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               writeInt2( totalParameterCount, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( totalDataCount, dst, dstIndex );
+               dstIndex += 2;
+               if( command != SMB_COM_TRANSACTION_SECONDARY ) {
+                       writeInt2( maxParameterCount, dst, dstIndex );
+                       dstIndex += 2;
+                       writeInt2( maxDataCount, dst, dstIndex );
+                       dstIndex += 2;
+                       dst[dstIndex++] = maxSetupCount;
+                       dst[dstIndex++] = (byte)0x00;           // Reserved1
+                       writeInt2( flags, dst, dstIndex );
+                       dstIndex += 2;
+                       writeInt4( timeout, dst, dstIndex );
+                       dstIndex += 4;
+                       dst[dstIndex++] = (byte)0x00;           // Reserved2
+                       dst[dstIndex++] = (byte)0x00;
+               }
+               writeInt2( parameterCount, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2(( parameterCount == 0 ? 0 : parameterOffset ), dst, dstIndex );
+               dstIndex += 2;
+               if( command == SMB_COM_TRANSACTION_SECONDARY ) {
+                       writeInt2( parameterDisplacement, dst, dstIndex );
+                       dstIndex += 2;
+               }
+               writeInt2( dataCount, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2(( dataCount == 0 ? 0 : dataOffset ), dst, dstIndex );
+               dstIndex += 2;
+               if( command == SMB_COM_TRANSACTION_SECONDARY ) {
+                       writeInt2( dataDisplacement, dst, dstIndex );
+                       dstIndex += 2;
+               } else {
+                       dst[dstIndex++] = (byte)setupCount;
+                       dst[dstIndex++] = (byte)0x00;           // Reserved3
+                       dstIndex += writeSetupWireFormat( dst, dstIndex );
+               }
+
+               return dstIndex - start;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+               int p = pad;
+
+               if( command == SMB_COM_TRANSACTION && isResponse() == false ) {
+                       dstIndex += writeString( name, dst, dstIndex );
+               }
+
+               if( parameterCount > 0 ) {
+                       while( p-- > 0 ) {
+                               dst[dstIndex++] = (byte)0x00;       // Pad
+                       }
+
+                       System.arraycopy( buf, bufParameterOffset, dst, dstIndex, parameterCount );
+                       dstIndex += parameterCount;
+               }
+
+               if( dataCount > 0 ) {
+                       p = pad1;
+                       while( p-- > 0 ) {
+                               dst[dstIndex++] = (byte)0x00;       // Pad1
+                       }
+                       System.arraycopy( buf, bufDataOffset, dst, dstIndex, dataCount );
+                       bufDataOffset += dataCount;
+                       dstIndex += dataCount;
+               }
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+
+       abstract int writeSetupWireFormat( byte[] dst, int dstIndex );
+       abstract int writeParametersWireFormat( byte[] dst, int dstIndex );
+       abstract int writeDataWireFormat( byte[] dst, int dstIndex );
+       abstract int readSetupWireFormat( byte[] buffer, int bufferIndex, int len );
+       abstract int readParametersWireFormat( byte[] buffer, int bufferIndex, int len );
+       abstract int readDataWireFormat( byte[] buffer, int bufferIndex, int len );
+
+       public String toString() {
+               return new String( super.toString() +
+                       ",totalParameterCount=" + totalParameterCount +
+                       ",totalDataCount=" + totalDataCount +
+                       ",maxParameterCount=" + maxParameterCount +
+                       ",maxDataCount=" + maxDataCount +
+                       ",maxSetupCount=" + (int)maxSetupCount +
+                       ",flags=0x" + Log.getHexString( flags, 2 ) +
+                       ",timeout=" + timeout +
+                       ",parameterCount=" + parameterCount +
+                       ",parameterOffset=" + parameterOffset +
+                       ",parameterDisplacement=" + parameterDisplacement +
+                       ",dataCount=" + dataCount +
+                       ",dataOffset=" + dataOffset +
+                       ",dataDisplacement=" + dataDisplacement +
+                       ",setupCount=" + setupCount +
+                       ",pad=" + pad +
+                       ",pad1=" + pad1 );
+       }
+}
diff --git a/src/jcifs/smb/SmbComTransactionResponse.java b/src/jcifs/smb/SmbComTransactionResponse.java
new file mode 100644 (file)
index 0000000..0cfc779
--- /dev/null
@@ -0,0 +1,158 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.util.Enumeration;
+import jcifs.Config;
+
+abstract class SmbComTransactionResponse extends ServerMessageBlock implements Enumeration {
+
+       // relative to headerStart
+       static final int SETUP_OFFSET        = 61;
+
+       static final int DISCONNECT_TID      = 0x01;
+       static final int ONE_WAY_TRANSACTION = 0x02;
+
+       static final int DEFAULT_TRANSACTION_BUF_SIZE = 0xFFFF;
+
+       int totalParameterCount;
+       int totalDataCount;
+       int parameterCount;
+       int parameterOffset;
+       int parameterDisplacement;
+       int dataCount;
+       int dataOffset;
+       int dataDisplacement;
+       int setupCount;
+       byte subCommand;
+       int pad;
+       int pad1;
+       boolean hasMore = true;
+       boolean isPrimary = true;
+
+       int data_rcv_buf_size;
+       byte[] buf;
+       int bufParameterStart;
+       int bufDataStart;
+
+       SmbComTransactionResponse() {
+               data_rcv_buf_size = Config.getInt( "jcifs.smb.client.transaction_buf_size",
+                                                                                                               DEFAULT_TRANSACTION_BUF_SIZE );
+               buf = new byte[data_rcv_buf_size]; // OUCH !!
+       }
+
+       public boolean hasMoreElements() {
+               return hasMore;
+       }
+       public Object nextElement() {
+               if( isPrimary ) {
+                       isPrimary = false;
+               }
+               return this;
+       }
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               int start = bufferIndex;
+
+               totalParameterCount = readInt2( buffer, bufferIndex );
+               if( bufDataStart == 0 ) {
+                       bufDataStart = totalParameterCount;
+               }
+               bufferIndex += 2;
+               totalDataCount = readInt2( buffer, bufferIndex );
+               bufferIndex += 4; // Reserved
+               parameterCount = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               parameterOffset = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               parameterDisplacement = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               dataCount = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               dataOffset = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               dataDisplacement = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               setupCount = buffer[bufferIndex] & 0xFF;
+               bufferIndex += 2;
+               if( setupCount != 0 ) {
+                       Log.println( Log.WARNINGS, "smb transaction response",
+                                                               "setupCount is not zero: " + setupCount );
+               }
+
+               return bufferIndex - start;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               pad = pad1 = 0;
+               int n;
+
+               if( parameterCount > 0 ) {
+                       bufferIndex += pad = parameterOffset - ( bufferIndex - headerStart );
+                       System.arraycopy( buffer, bufferIndex, buf,
+                                                       bufParameterStart + parameterDisplacement, parameterCount );
+                       bufferIndex += parameterCount;
+               }
+               if( dataCount > 0 ) {
+                       bufferIndex += pad1 = dataOffset - ( bufferIndex - headerStart );
+                       System.arraycopy( buffer, bufferIndex, buf,
+                                                       bufDataStart + dataDisplacement, dataCount );
+                       bufferIndex += dataCount;
+               }
+
+               /* Check to see if the entire transaction has been
+                * read. If so call the read methods.
+                */
+
+               if(( parameterDisplacement + parameterCount ) == totalParameterCount &&
+                               ( dataDisplacement + dataCount ) == totalDataCount ) {
+                       hasMore = false;
+                       readParametersWireFormat( buf, bufParameterStart, totalParameterCount );
+                       readDataWireFormat( buf, bufDataStart, totalDataCount );
+               }
+
+               return pad + parameterCount + pad1 + dataCount;
+       }
+
+       abstract int writeSetupWireFormat( byte[] dst, int dstIndex );
+       abstract int writeParametersWireFormat( byte[] dst, int dstIndex );
+       abstract int writeDataWireFormat( byte[] dst, int dstIndex );
+       abstract int readSetupWireFormat( byte[] buffer, int bufferIndex, int len );
+       abstract int readParametersWireFormat( byte[] buffer, int bufferIndex, int len );
+       abstract int readDataWireFormat( byte[] buffer, int bufferIndex, int len );
+
+       public String toString() {
+               return new String( super.toString() +
+                       ",totalParameterCount=" + totalParameterCount +
+                       ",totalDataCount=" + totalDataCount +
+                       ",parameterCount=" + parameterCount +
+                       ",parameterOffset=" + parameterOffset +
+                       ",parameterDisplacement=" + parameterDisplacement +
+                       ",dataCount=" + dataCount +
+                       ",dataOffset=" + dataOffset +
+                       ",dataDisplacement=" + dataDisplacement +
+                       ",setupCount=" + setupCount +
+                       ",pad=" + pad +
+                       ",pad1=" + pad1 );
+       }
+}
diff --git a/src/jcifs/smb/SmbComTreeConnectAndX.java b/src/jcifs/smb/SmbComTreeConnectAndX.java
new file mode 100644 (file)
index 0000000..7363cb9
--- /dev/null
@@ -0,0 +1,191 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.Config;
+import jcifs.util.PropertiesTree;
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComTreeConnectAndX extends AndXServerMessageBlock {
+
+       SmbSession session;
+       boolean disconnectTid = false;
+       String path, service;
+       byte[] password;
+       int passwordLength;
+
+       /* batchLimits indecies
+        *
+        * 0 = SMB_COM_CHECK_DIRECTORY
+        * 1 = SMB_COM_COPY
+        * 2 = SMB_COM_CREATE_DIRECTORY
+        * 3 = SMB_COM_DELETE
+        * 4 = SMB_COM_DELETE_DIRECTORY
+        * 5 = SMB_COM_OPEN_ANDX
+        * 6 = SMB_COM_RENAME
+        * 7 = SMB_COM_TRANSACTION
+        * 8 = SMB_COM_QUERY_INFORMATION
+        */
+
+       /* All batch limits are single batch only until further notice
+        */
+
+       static byte[] batchLimits = {
+               1, 1, 1, 1, 1, 1, 1, 1, 0
+       };
+
+       static {
+               PropertiesTree pt = (PropertiesTree)Config.get( "jcifs.smb.client.TreeConnectAndX" );
+               String s;
+
+               if( pt != null ) {
+                       if(( s = pt.getProperty( "CheckDirectory" )) != null ) {
+                               batchLimits[0] = Byte.parseByte( s );
+                       }
+                       if(( s = pt.getProperty( "Copy" )) != null ) {
+                               batchLimits[1] = Byte.parseByte( s );
+                       }
+                       if(( s = pt.getProperty( "CreateDirectory" )) != null ) {
+                               batchLimits[2] = Byte.parseByte( s );
+                       }
+                       if(( s = pt.getProperty( "Delete" )) != null ) {
+                               batchLimits[3] = Byte.parseByte( s );
+                       }
+                       if(( s = pt.getProperty( "DeleteDirectory" )) != null ) {
+                               batchLimits[4] = Byte.parseByte( s );
+                       }
+                       if(( s = pt.getProperty( "OpenAndX" )) != null ) {
+                               batchLimits[5] = Byte.parseByte( s );
+                       }
+                       if(( s = pt.getProperty( "Rename" )) != null ) {
+                               batchLimits[6] = Byte.parseByte( s );
+                       }
+                       if(( s = pt.getProperty( "Transaction" )) != null ) {
+                               batchLimits[7] = Byte.parseByte( s );
+                       }
+                       if(( s = pt.getProperty( "QueryInformation" )) != null ) {
+                               batchLimits[8] = Byte.parseByte( s );
+                       }
+               }
+       }
+
+       SmbComTreeConnectAndX( SmbSession session, String path,
+                                                               String service, ServerMessageBlock andx ) {
+               super( andx );
+               this.session = session;
+               this.path = path;
+               this.service = service;
+               command = SMB_COM_TREE_CONNECT_ANDX;
+       }
+
+       int getBatchLimit( byte command ) {
+               int c = (int)( command & 0xFF );
+               switch( c ) {
+                       case SMB_COM_CHECK_DIRECTORY:
+                               return batchLimits[0];
+                       case SMB_COM_COPY:
+                               return batchLimits[1];
+                       case SMB_COM_CREATE_DIRECTORY:
+                               return batchLimits[2];
+                       case SMB_COM_DELETE:
+                               return batchLimits[3];
+                       case SMB_COM_DELETE_DIRECTORY:
+                               return batchLimits[4];
+                       case SMB_COM_OPEN_ANDX:
+                               return batchLimits[5];
+                       case SMB_COM_RENAME:
+                               return batchLimits[6];
+                       case SMB_COM_TRANSACTION:
+                               return batchLimits[7];
+                       case SMB_COM_QUERY_INFORMATION:
+                               return batchLimits[8];
+               }
+               return 0;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+
+               if( session.transport.server.security == SECURITY_SHARE &&
+                                                                                                       session.password.length() != 0 ) {
+                       if( session.transport.server.encryptedPasswords ) {
+                               // encrypted
+                               password = SmbSession.getPreNTLMResponse( session.password,
+                                                                                       session.transport.server.encryptionKey );
+                               passwordLength = 24;
+                       } else {
+                               // plain text
+                               throw new RuntimeException( "plain text passwords not implemented" );
+                       }
+               } else {
+                       // no password in tree connect
+                       passwordLength = 1;
+               }
+
+               dst[dstIndex++] = (byte)0x00;
+               dst[dstIndex++] = disconnectTid ? (byte)0x01 : (byte)0x00;
+               writeInt2( passwordLength, dst, dstIndex );
+               return 4;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               if( session.transport.server.security == SECURITY_SHARE &&
+                                                                                                       session.password.length() != 0 ) {
+                       if( session.transport.server.encryptedPasswords ) {
+                               // encrypted
+                               System.arraycopy( password, 0, dst, dstIndex, passwordLength );
+                               dstIndex += passwordLength;
+                       } else {
+                               // plain text
+                               throw new RuntimeException( "plain text passwords not implemented" );
+                       }
+               } else {
+                       // no password in tree connect
+                       dst[dstIndex++] = (byte)0x00;
+               }
+               dstIndex += writeString( path, dst, dstIndex );
+               System.arraycopy( service.getBytes(), 0, dst, dstIndex, service.length() );
+               dstIndex += service.length();
+               dst[dstIndex++] = (byte)'\0';
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               String result = new String( "SmbComTreeConnectAndX[" +
+                       super.toString() +
+                       ",disconnectTid=" + disconnectTid +
+                       ",passwordLength=" + passwordLength +
+                       ",password=" + Log.getHexString(
+                                               password, passwordLength, 0 ) +
+                       ",path=" + path +
+                       ",service=" + service + "]" );
+               return result;
+       }
+}
+
diff --git a/src/jcifs/smb/SmbComTreeConnectAndXResponse.java b/src/jcifs/smb/SmbComTreeConnectAndXResponse.java
new file mode 100644 (file)
index 0000000..fd53dd6
--- /dev/null
@@ -0,0 +1,75 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComTreeConnectAndXResponse extends AndXServerMessageBlock {
+
+       static final int SMB_SUPPORT_SEARCH_BITS = 0x0001;
+       static final int SMB_SHARE_IS_IN_DFS     = 0x0002;
+
+       boolean supportSearchBits, shareIsInDfs;
+       String service, nativeFileSystem = "";
+
+       SmbComTreeConnectAndXResponse( ServerMessageBlock andx ) {
+               super( andx );
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               supportSearchBits = ( buffer[bufferIndex] & SMB_SUPPORT_SEARCH_BITS ) ==
+                                                                                       SMB_SUPPORT_SEARCH_BITS ? true : false;
+               shareIsInDfs = ( buffer[bufferIndex] & SMB_SHARE_IS_IN_DFS ) ==
+                                                                                       SMB_SHARE_IS_IN_DFS ? true : false;
+               return 2;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               int start = bufferIndex;
+
+               int len = readStringLength( buffer, bufferIndex, 32 );
+               service = new String( buffer, bufferIndex, len );
+               bufferIndex += len + 1;
+               // win98 observed not returning nativeFileSystem
+               if( byteCount > bufferIndex - start ) {
+                       nativeFileSystem = readString( buffer, bufferIndex );
+                       bufferIndex += stringWireLength( nativeFileSystem, bufferIndex );
+               }
+
+               return bufferIndex - start;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               String result = new String( "SmbComTreeConnectAndXResponse[" +
+                       super.toString() +
+                       ",supportSearchBits=" + supportSearchBits +
+                       ",shareIsInDfs=" + shareIsInDfs +
+                       ",service=" + service +
+                       ",nativeFileSystem=" + nativeFileSystem + "]" );
+               return result;
+       }
+}
diff --git a/src/jcifs/smb/SmbComTreeDisconnect.java b/src/jcifs/smb/SmbComTreeDisconnect.java
new file mode 100644 (file)
index 0000000..ca8d101
--- /dev/null
@@ -0,0 +1,43 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class SmbComTreeDisconnect extends ServerMessageBlock {
+
+       SmbComTreeDisconnect() {
+               command = SMB_COM_TREE_DISCONNECT;
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComTreeDisconnect[" +
+                       super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComWriteAndX.java b/src/jcifs/smb/SmbComWriteAndX.java
new file mode 100644 (file)
index 0000000..c77f3e0
--- /dev/null
@@ -0,0 +1,122 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.Config;
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComWriteAndX extends AndXServerMessageBlock {
+
+       static final int READ_ANDX_BATCH_LIMIT =
+                                                       Config.getInt( "jcifs.smb.client.WriteAndX.ReadAndX", 1 );
+       static final int CLOSE_BATCH_LIMIT =
+                                                       Config.getInt( "jcifs.smb.client.WriteAndX.Close", 1 );
+
+       int fid,
+               offset,
+               writeMode,
+               remaining,
+               dataLength,
+               dataOffset,
+               off,
+               pad;
+       byte[] b;
+
+       SmbComWriteAndX( int fid, int offset, int remaining,
+                                       byte[] b, int off, int len, ServerMessageBlock andx ) {
+               super( andx );
+               this.fid = fid;
+               this.offset = offset;
+               this.remaining = remaining;
+               this.b = b;
+               this.off = off;
+               dataLength = len;
+               command = SMB_COM_WRITE_ANDX;
+       }
+
+       int getBatchLimit( byte command ) {
+               if( command == SMB_COM_READ_ANDX ) {
+                       return READ_ANDX_BATCH_LIMIT;
+               }
+               if( command == SMB_COM_CLOSE ) {
+                       return CLOSE_BATCH_LIMIT;
+               }
+               return 0;
+       }
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               dataOffset = dstIndex + 22; // 22 = off from here to pad
+               pad = ( dataOffset - headerStart ) % 4;
+               pad = pad == 0 ? 0 : 4 - pad;
+               dataOffset += pad;
+
+               writeInt2( fid, dst, dstIndex );
+               dstIndex += 2;
+               writeInt4( offset, dst, dstIndex );
+               dstIndex += 4;
+               for( int i = 0; i < 4; i++ ) {
+                       dst[dstIndex++] = (byte)0x00;
+               }
+               writeInt2( writeMode, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( remaining, dst, dstIndex );
+               dstIndex += 2;
+               dst[dstIndex++] = (byte)0x00;
+               dst[dstIndex++] = (byte)0x00;
+               writeInt2( dataLength, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( dataOffset, dst, dstIndex );
+               dstIndex += 2;
+               // offsetHigh another day
+
+               return dstIndex - start;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               while( pad-- > 0 ) {
+                       dst[dstIndex++] = (byte)0x00;
+               }
+               System.arraycopy( b, off, dst, dstIndex, dataLength );
+               dstIndex += dataLength;
+
+               return dstIndex - start;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComWriteAndX[" +
+                       super.toString() +
+                       ",fid=" + fid +
+                       ",offset=" + offset +
+                       ",writeMode=" + writeMode +
+                       ",remaining=" + remaining +
+                       ",dataLength=" + dataLength +
+                       ",dataOffset=" + dataOffset + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbComWriteAndXResponse.java b/src/jcifs/smb/SmbComWriteAndXResponse.java
new file mode 100644 (file)
index 0000000..8d802b0
--- /dev/null
@@ -0,0 +1,52 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class SmbComWriteAndXResponse extends AndXServerMessageBlock {
+
+       int count;
+
+       SmbComWriteAndXResponse() {
+       }
+
+       int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeBytesWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) {
+               count = readInt2( buffer, bufferIndex );
+               return 8;
+       }
+       int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+               return 0;
+       }
+       int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
+               return 0;
+       }
+       public String toString() {
+               return new String( "SmbComWriteAndXResponse[" +
+                       super.toString() +
+                       ",count=" + count + "]" );
+       }
+}
diff --git a/src/jcifs/smb/SmbException.java b/src/jcifs/smb/SmbException.java
new file mode 100644 (file)
index 0000000..e9bfd06
--- /dev/null
@@ -0,0 +1,202 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.IOException;
+
+class SmbException extends IOException {
+
+       // error classes
+       static final int SUCCESS = 0;
+       static final int ERRDOS  = 0x01;
+       static final int ERRSRV  = 0x02;
+       static final int ERRHRD  = 0x03;
+       static final int ERRCMD  = 0xFF;
+
+       // dos error codes
+       static final int ERRbadfunc        = 1;
+       static final int ERRbadfile        = 2;
+       static final int ERRbadpath        = 3;
+       static final int ERRnoaccess   = 5;
+       static final int ERRbadfid     = 6;
+       static final int ERRbadshare   = 32;
+       static final int ERRbadnetname = 67;
+       static final int ERRbadparm        = 87;
+       static final int ERRfilexists  = 80;
+       static final int ERRbrokenpipe = 109;
+       static final int ERRinvname        = 123;
+       static final int ERRpipebusy   = 231;
+       static final int ERRnodata     = 232;
+
+       // srv error codes
+       static final int ERRerror           = 1;
+       static final int ERRbadpw           = 2;
+       static final int ERRaccess          = 4;
+       static final int ERRinvnid          = 5;
+       static final int ERRinvnetname      = 6;
+       static final int ERRbaduid          = 91;
+       static final int ERRaccountExpired  = 2239;
+       static final int ERRbadClient       = 2240;
+       static final int ERRbadLogonTime    = 2241;
+       static final int ERRpasswordExpired = 2242;
+
+       // hrd error codes
+       static final int ERRnowrite  = 19;
+       static final int ERRnotready = 21;
+
+       int errorClass;
+       int errorCode;
+
+       static String getErrorString( int errorClass, int errorCode ) {
+               String result = "";
+               switch( errorClass ) {
+                       case SUCCESS:
+                               result += "SUCCESS";
+                               break;
+                       case ERRDOS:
+                               result += "ERRDOS/";
+                               switch( errorCode ) {
+                                       case ERRbadfunc:
+                                               result += "ERRbadfunc: Invalid function";
+                                               break;
+                                       case ERRbadfile:
+                                               result += "ERRbadfile: File not found";
+                                               break;
+                                       case ERRbadpath:
+                                               result += "ERRbadpath: Directory invalid";
+                                               break;
+                                       case ERRnoaccess:
+                                               result += "ERRnoaccess: Access denied";
+                                               break;
+                                       case ERRbadparm:
+                                               result += "ERRbadparm: Invalid parameter";
+                                               break;
+                                       case ERRinvname:
+                                               result += "ERRinvname: Invalid name";
+                                               break;
+                                       case ERRfilexists:
+                                               result += "ERRfilexists: File exists";
+                                               break;
+                                       case ERRbadfid:
+                                               result += "ERRbadfid: Invalid file handle";
+                                               break;
+                                       case ERRbadshare:
+                                               result += "ERRbadshare: The file is being used by another process";
+                                               break;
+                                       case ERRnotready:
+                                               result += "ERRnotready: The device is not ready";
+                                               break;
+                                       case ERRbadnetname:
+                                               result += "ERRbadnetname: The network name cannot be found.";
+                                               break;
+                                       case ERRpipebusy:
+                                               result += "ERRpipebusy: All pipe instances are busy.";
+                                               break;
+                                       case ERRnodata:
+                                               result += "ERRnodata: The pipe is being closed.";
+                                               break;
+                                       case ERRbrokenpipe:
+                                               result += "ERRbrokenpipe: The pipe has been ended.";
+                                               break;
+                                       default:
+                                               result += "Ehh, one of the other ones. Please update " +
+                                                                               "getErrorString for errorCode=" + errorCode;
+                               }
+                               break;
+                       case ERRSRV:
+                               result += "ERRSRV/";
+                               switch( errorCode ) {
+                                       case ERRerror:
+                                               result += "ERRerror: Non-specific error code";
+                                               break;
+                                       case ERRbadpw:
+                                               result += "ERRbadpw: Bad password";
+                                               break;
+                                       case ERRinvnid:
+                                               result += "ERRinvnid: The Tid specified was invalid";
+                                               break;
+                                       case ERRinvnetname:
+                                               result += "ERRinvnetname: Invalid network name in tree connect, " +
+                                                                                       "service not found";
+                                               break;
+                                       case ERRbaduid:
+                                               result += "ERRbaduid: The UID is not known as a valid user " +
+                                                                                       "identifier on this session";
+                                               break;
+                                       case ERRaccess:
+                                               result += "ERRaccess: The client does not have the necessary " +
+                                                                                       "access rights for the requested function";
+                                               break;
+                                       case ERRaccountExpired:
+                                               result += "ERRaccountExpired: The user account has expired";
+                                               break;
+                                       case ERRbadClient:
+                                               result += "ERRbadClient: The user is not allowed to access " +
+                                                                                       "this server from this client";
+                                               break;
+                                       case ERRbadLogonTime:
+                                               result += "ERRbadLogonTime: The user is not permitted to access " +
+                                                                                       "the server at this time";
+                                               break;
+                                       case ERRpasswordExpired:
+                                               result += "ERRpasswordExpired: The password of the user has " +
+                                                                                       "expired. Please change your password.";
+                                               break;
+                                       default:
+                                               result += "Ehh, one of the other ones. Please update " +
+                                                                                       "getErrorString for errorCode=" + errorCode;
+                               }
+                               break;
+                       case ERRHRD:
+                               result += "ERRHRD/";
+                               switch( errorCode ) {
+                                       case ERRnowrite:
+                                               result += "ERRnowrite: Attempt to write on write-protected media";
+                                               break;
+                                       case ERRnotready:
+                                               result += "ERRnotready: The device is not ready";
+                                               break;
+                                       default:
+                                               result += "Ehh, one of the other ones. Please update " +
+                                                               "getErrorString for errorCode=" + errorCode;
+                               }
+                               break;
+                       case ERRCMD:
+                               result += "ERRCMD: Command was not in the \"SMB\" format";
+                               break;
+                       default:
+                               result += "unknown error class: " + errorClass;
+               }
+               return result;
+       }
+       static String getErrorString( int code ) {
+               if( code == 0 ) {
+                       return "0x00000000";
+               }
+               return getErrorString( code & 0xFF, ( code >> 16 ) & 0xFFFF );
+       }
+
+       public SmbException() {
+       }
+       public SmbException( int code ) {
+               super( getErrorString( code & 0xFF, ( code >> 16 ) & 0xFFFF ));
+               errorClass = code & 0xFF;
+               errorCode = ( code >> 16 ) & 0xFFFF;
+       }
+}
diff --git a/src/jcifs/smb/SmbFile.java b/src/jcifs/smb/SmbFile.java
new file mode 100644 (file)
index 0000000..a4dd454
--- /dev/null
@@ -0,0 +1,910 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.netbios.NbtAddress;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.net.URL;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * This class represents a resource on an SMB network. Mainly these
+ * resources are files and directories however an <code>SmbFile</code>
+ * may also refer to servers and workgroups. If the resource is a file or
+ * directory the methods of <code>SmbFile</code> follow the behavior of
+ * the well known {@link java.io.File} class. One fundamental difference
+ * is the usage of a URL scheme<b>*</b> to specify the target file or
+ * directory. SmbFile URLs have the following syntax:
+ *
+ * <blockquote><pre>
+ *     smb://[[[domain;]username[:password]@]server[:port][/share[/path]]]
+ * </pre></blockquote>
+ *
+ * This example:
+ *
+ * <blockquote><pre>
+ *     smb://storage15/public/foo.txt
+ * </pre></blockquote>
+ *
+ * would referece the file <code>foo.txt</code> in the share
+ * <code>public</code> on the server <code>storage15</code>. In addition
+ * to referencing files and directories, jCIFS can also address servers,
+ * and workgroups. When used in conjunction with the <code>list</code>
+ * method, this functionality can be usefull for network diagnostics
+ * tools or "Network Neighborhood" like functionality. The server
+ * component may a traditional NetBIOS name, a DNS name, or IP
+ * address. These name resolution mechanisms and their resolution order
+ * can be changed (See <a href="../../../resolver.html">Setting Name
+ * Resolution Properties</a>). The servername and path components are
+ * not case sensitive but the domain, username, and password components
+ * are. It is also likely that properties must be specified for jcifs
+ * to function (See <a href="../../overview-summary.html#scp">Setting
+ * JCIFS Properties</a>). Here are some examples of SMB URLs with brief
+ * descriptions of what they do:
+ *
+ * <p><b>*</b> This URL scheme conforms to the <a target="_top"
+ * href="http://www.ietf.org/internet-drafts/draft-crhertel-smb-url-00.txt">SMB
+ * Filesharing URL Scheme</a> IETF draft.
+ * 
+ * <p><table border="1" cellpadding="3" cellspacing="0" width="100%">
+ * <tr bgcolor="#ccccff">
+ * <td colspan="2"><b>SMB URL Examples</b></td>
+ * <tr><td width="20%"><b>URL</b></td><td><b>Description</b></td></tr>
+ * 
+ * <tr><td width="20%"><code>smb://users-nyc;miallen:mypass@angus/tmp</code></td><td>
+ * This URL references a share called <code>tmp</code> on the server
+ * <code>angus</code> as user <code>miallen</code> who's password is
+ * <code>mypass</code>.
+ * </td></tr>
+ * 
+ * <tr><td width="20%">
+ * <code>smb://Administrator:P@ss@msmith1/c/WINDOWS/Desktop/foo.txt</code></td><td>
+ * A relativly sophisticated example that references a file
+ * <code>msmith1</code>'s desktop as user <code>Administrator</code>.
+ * </td></tr>
+ * 
+ * <tr><td width="20%"><code>smb://angus</code></td><td>
+ * This references only a server. The behavior of some methods is different
+ * in this context(e.g. you cannot <code>delete</code> a server) however
+ * as you might expect the <code>list</code> method will list the available
+ * shares on this server.
+ * </td></tr>
+ * 
+ * <tr><td width="20%"><code>smb://myworkgroup</code></td><td>
+ * This syntactically is identical to the above example. However if
+ * <code>myworkgroup</code> happends to be a workgroup(which is indeed
+ * suggested by the name) the <code>list</code> method will return
+ * a list of servers that have registered themselves as members of
+ * <code>myworkgroup</code>.
+ * </td></tr>
+ * 
+ * <tr><td width="20%"><code>smb://</code></td><td>
+ * Just as <code>smb://server</code> lists shares and
+ * <code>smb://workgroup</code> lists servers, the <code>smb://</code>
+ * URL lists all available workgroups on a netbios LAN. Again,
+ * in this context many methods are not valid and return default
+ * values(e.g. <code>isHidden</code> and <code>renameTo</code> will always
+ * return false).
+ * </td></tr>
+ * 
+ * <tr><td width="20%"><code>smb://angus.foo.net/d/jcifs/pipes.doc</code></td><td>
+ * The server name may also be a DNS name as it is in this example. See
+ * <a href="../../../resolver.html">Setting Name Resolution Properties</a>
+ * for details.
+ * </td></tr>
+ * 
+ * <tr><td width="20%"><code>smb://192.168.1.15/ADMIN$</code></td><td>
+ * The server name may also be an IP address. See <a
+ * href="../../../resolver.html">Setting Name Resolution Properties</a>
+ * for details.
+ * </td></tr>
+ * 
+ * <tr><td width="20%">
+ * <code>smb://domain;username:password@server/share/path/to/file.txt</code></td><td>
+ * A prototypical example that uses all the fields.
+ * </td></tr>
+ * 
+ * <tr><td width="20%"><code>smb://myworkgroup/angus &lt;-- ILLEGAL </code></td><td>
+ * Despite the hierarchial relationship between workgroups, servers, and
+ * filesystems this example is not valid.
+ * </td></tr>
+ * 
+ * </table>
+ * 
+ * <p>A second constructor argument may be specified to augment the URL
+ * for better programmatic control when processing many files under
+ * a common base. This is slightly different from the corresponding
+ * <code>java.io.File</code> usage; a '/' at the beginning of the second
+ * parameter will still use the server component of the first parameter. The
+ * examples below illustrate the resulting URLs when this second contructor
+ * argument is used.
+ *
+ * <p><table border="1" cellpadding="3" cellspacing="0" width="100%">
+ * <tr bgcolor="#ccccff">
+ * <td colspan="3">
+ * <b>Examples Of SMB URLs When Augmented With A Second Constructor Parameter</b></td>
+ * <tr><td width="20%">
+ * <b>First Parameter</b></td><td><b>Second Parameter</b></td><td><b>Result</b></td></tr>
+ *
+ * <tr><td width="20%"><code>
+ *     smb://host/share/a/b
+ * </code></td><td width="20%"><code>
+ *     c/d
+ * </code></td><td><code>
+ *     smb://host/share/a/b/c/d
+ * </code></td></tr>
+ * 
+ * <tr><td width="20%"><code>
+ *     smb://host/share/foo/bar
+ * </code></td><td width="20%"><code>
+ *     /share2/zig/zag
+ * </code></td><td><code>
+ *     smb://host/share2/zig/zag
+ * </code></td></tr>
+ * 
+ * <tr><td width="20%"><code>
+ *     smb://host/share/foo/bar
+ * </code></td><td width="20%"><code>
+ *     ../zip
+ * </code></td><td><code>
+ *     smb://host/share/foo/zip
+ * </code></td></tr>
+ * 
+ * <tr><td width="20%"><code>
+ *     smb://host/share/zig/zag
+ * </code></td><td width="20%"><code>
+ *     smb://foo/bar
+ * </code></td><td><code>
+ *     smb://foo/bar
+ * </code></td></tr>
+ * 
+ * <tr><td width="20%"><code>
+ *     smb://host/share/foo
+ * </code></td><td width="20%"><code>
+ *     ../.././.././../foo
+ * </code></td><td><code>
+ *     smb://foo
+ * </code></td></tr>
+ * 
+ * <tr><td width="20%"><code>
+ *     smb://host/share/zig/zag
+ * </code></td><td width="20%"><code>
+ *     null
+ * </code></td><td><code>
+ *     smb://host/share/zig/zag
+ * </code></td></tr>
+ * 
+ * <tr><td width="20%"><code>
+ *     smb://host/share/zig/zag
+ * </code></td><td width="20%"><code>
+ *     /
+ * </code></td><td><code>
+ *     smb://host
+ * </code></td></tr>
+ * 
+ * <tr><td width="20%"><code>
+ *     smb://server
+ * </code></td><td width="20%"><code>
+ *     ..
+ * </code></td><td><code>
+ *     smb://
+ * </code></td></tr>
+ * 
+ * <tr><td width="20%"><code>
+ *     smb://
+ * </code></td><td width="20%"><code>
+ *     myworkgroup
+ * </code></td><td><code>
+ *     smb://myworkgroup
+ * </code></td></tr>
+ * 
+ * <tr><td width="20%"><code>
+ *     smb://myworkgroup
+ * </code></td><td width="20%"><code>
+ *     angus
+ * </code></td><td><code>
+ *     smb://angus
+ * </code></td></tr>
+ * 
+ * </table>
+ *
+ * <p>Notice there are two exceptional examples where the workgroup
+ * resource <code>smb://myworkgroup</code> and server <code>angus</code>
+ * are combined to produce just <code>smb://angus</code> and not
+ * <code>smb://myworkgroup/angus</code>. Similarly, when combining
+ * <code>smb://angus</code> with <code>..</code>,
+ * angus' workgroup resource <code>smb://myworkgroup</code> is <i>not</i>
+ * returned. This is by design and in accordance with the <a target="_top"
+ * href="http://www.ietf.org/internet-drafts/draft-crhertel-smb-url-00.txt">SMB
+ * Filesharing URL Scheme</a> IETF draft.
+ *
+ * <p>Instances of the <code>SmbFile</code> class are immutable; that is,
+ * once created, the abstract pathname represented by an SmbFile object
+ * will never change.
+ *
+ * @see       java.io.File
+ * @since     jcifs-0.4
+ */
+
+public class SmbFile {
+
+       // these are shifted for use in flags
+       static final int O_RDONLY = 0x010000;
+       static final int O_WRONLY = 0x020000;
+       static final int O_RDWR   = 0x030000;
+       static final int O_APPEND = 0x040000;
+
+       // Open Function Encoding
+       // create if the file does not exist
+       static final int O_CREAT  = 0x0010;
+       // fail if the file exists
+       static final int O_EXCL   = 0x0001;
+       // truncate if the file exists
+       static final int O_TRUNC  = 0x0002;
+
+       // file attribute encoding
+       static final int ATTR_READONLY   = 0x01;
+       static final int ATTR_HIDDEN     = 0x02;
+       static final int ATTR_SYSTEM     = 0x04;
+       static final int ATTR_VOLUME     = 0x08;
+       static final int ATTR_DIRECTORY  = 0x10;
+       static final int ATTR_ARCHIVE    = 0x20;
+
+       static {
+               // is this needed ??
+               try {
+                       Class.forName( "jcifs.Config" );
+               } catch( ClassNotFoundException cnfe ) {
+                       cnfe.printStackTrace();
+               }
+       }
+
+       SmbURL url;
+       String path;
+       SmbTree tree;
+       int fid, tid, hash;
+       int attributes = ATTR_READONLY | ATTR_DIRECTORY;
+       long lastModified, size;
+       boolean opened, isPipe;
+       NbtAddress address;
+
+/** 
+ * Constructs an SmbFile representing a resource on an SMB network such as
+ * a file or directory. See the description and examples of smb URLs above.
+ *
+ * @param   url A URL string
+ * @throws  MalformedURLException
+ *          If the <code>parent</code> and <code>child</code> parameters
+ *          do not follow the prescribed syntax
+ * @throws  UnknownHostException
+ *          If the name of a server specified cannot be resolved using
+ *          the configured name resolution methods
+ */
+
+       public SmbFile( String url ) throws MalformedURLException, UnknownHostException {
+               this( url, null );
+       }
+
+/**
+ * Constructs an SmbFile representing a resource on an SMB network such
+ * as a file or directory. The second parameter is a relative path from
+ * the <code>parent SmbFile</code>. See the description above for examples
+ * of using the second <code>name</code> parameter.
+ *
+ * @param   parent A base <code>SmbFile</code>
+ * @param   child A path string relative to the <code>parent</code> paremeter
+ * @throws  MalformedURLException
+ *          If the <code>parent</code> and <code>child</code> parameters
+ *          do not follow the prescribed syntax
+ * @throws  UnknownHostException
+ *          If the name of a server specified cannot be resolved using
+ *          the configured name resolution methods
+ */
+
+       public SmbFile( SmbFile parent, String child ) throws MalformedURLException,
+                                                                                                                               UnknownHostException {
+               this( parent.getCanonicalPath(), child );
+       }
+
+/**
+ * Constructs an SmbFile representing a resource on an SMB network such
+ * as a file or directory. The second parameter is a relative path from
+ * the <code>parent</code>. See the description above for examples of
+ * using the second <code>chile</code> parameter.
+ *
+ * @param   parent A URL string
+ * @param   child A path string relative to the <code>parent</code> paremeter
+ * @throws  MalformedURLException
+ *          If the <code>parent</code> and <code>child</code> parameters
+ *          do not follow the prescribed syntax
+ * @throws  UnknownHostException
+ *          If the name of a server specified cannot be resolved using
+ *          the configured name resolution methods
+ */
+
+       public SmbFile( String parent, String child ) throws MalformedURLException,
+                                                                                                                               UnknownHostException {
+               String share = "IPC$";
+               String unc;
+               String username = "";
+               String password = "";
+               String domain = "";
+               SmbTransport trans;
+               SmbSession ssn;
+
+               url = new SmbURL( parent, child );
+
+               if( url.isWorkgroup ) {
+                       address = NbtAddress.getByName( url.server, 0x1d, null );
+                       // Cannot est. session using name WORKGROUP<1D> so convert to IP<20> to force rev. lookup
+                       address = NbtAddress.getByName( address.getHostAddress(), 0x20, null );
+               } else if( url.server != null && url.share != null ) {
+                       address = NbtAddress.getByName( url.server, 0x20, null );
+                       username = url.username;
+                       password = url.password;
+                       domain = url.domain;
+                       share = url.share;
+               } else if( url.server != null ) {
+                       address = NbtAddress.getByName( url.server, 0x20, null );
+                       username = url.username;
+                       password = url.password;
+                       domain = url.domain;
+               } else {
+                       address = NbtAddress.getByName( NbtAddress.MASTER_BROWSER_NAME, 0x01, null );
+                       // Cannot est. session using name __MSBROWSE__<01> so convert to IP<20> to force rev. lookup
+                       address = NbtAddress.getByName( address.getHostAddress(), 0x20, null );
+               }
+
+               trans = SmbTransport.getSmbTransport( address, url.port );
+               ssn = trans.getSmbSession( username, password, domain );
+               unc = new String( "\\\\" + address.getHostName() + "\\" + share ).toUpperCase();
+               tree = ssn.getSmbTree( unc, null );
+
+               if( url.canonicalPath == null ) {
+                       path = "\\";
+               } else {
+                       path = url.canonicalPath.replace( '/', '\\' );
+               }
+               opened = false;
+       }
+
+       boolean isOpen() {
+               if( opened && tree.treeConnected && tid == tree.tid ) {
+                       return true;
+               }
+               return false;
+       }
+       void open( int flags ) throws IOException {
+               if( isOpen() ) {
+                       return;
+               }
+               fid = tree.open( path, flags );
+               tid = tree.tid;
+               opened = true;
+       }
+       void close() throws IOException {
+               if( isOpen() == false ) {
+                       return;
+               }
+               opened = false;
+
+               Log.println( Log.WARNINGS, "smb close warning",
+                               " fid=" + fid );
+
+               /*
+                * Close Request / Response
+                */
+
+               tree.send( new SmbComClose( fid ), new SmbComBlankResponse() );
+       }
+
+
+/**
+ * Returns the last component of the target URL. This will
+ * effectively be the name of the file or directory represented by this
+ * <code>SmbFile</code> or in the case of URLs that only specify a server
+ * or workgroup, the server or workgroup will be returned. The name of
+ * the root URL <code>smb://</code> is also <code>smb://</code>.
+ *
+ * @return  The last component of the URL associated with this SMB
+ *          resource or <code>smb://</code> if the resource is <code>smb://</code>
+ *          itself.
+ */
+
+       public String getName() {
+               String result;
+               int p;
+
+               if( url.server == null ) {
+                       return "smb://";
+               }
+               result = url.toString();
+               p = result.lastIndexOf( '/' );
+               return result.substring( p + 1 );
+       }
+
+/**
+ * Everything but the last component of the URL representing this SMB
+ * resource is effectivly it's parent. The root URL <code>smb://</code>
+ * does not have a parent. In this case <code>smb://</code> is returned.
+ *
+ * @return   The parent directory of this SMB resource or
+ *           <code>smb://</code> if the resource refers to the root of the URL
+ *           hierarchy which incedentally is also <code>smb://</code>.
+ */
+
+       public String getParent() {
+               String result;
+               int p;
+
+               if( url.share == null ) {
+                       return "smb://";
+               }
+               result = url.toString();
+               p = result.lastIndexOf( '/' );
+               return result.substring( 0, p );
+       }
+
+/**
+ * Returns the full uncanonicalized URL of this SMB resource. An
+ * <code>SmbFile</code> constructed with the result of this method will
+ * result in an <code>SmbFile</code> that is equal to the original.
+ *
+ * @return  The uncanonicalized full URL of this SMB resource.
+ */
+
+       public String getPath() {
+               return url.toString();
+       }
+
+/**
+ * Returns the full URL of this SMB resource with '.' and '..' components
+ * factored out. An <code>SmbFile</code> constructed with the result of
+ * this method will result in an <code>SmbFile</code> that is equal to
+ * the original.
+ *
+ * @return  The canonicalized URL of this SMB resource.
+ */
+
+       public String getCanonicalPath() {
+               return url.getCanonicalPath();
+       }
+
+/**
+ * Retrieves the share associated with this SMB resource. In
+ * the case of <code>smb://</code>, <code>smb://workgroup</code>,
+ * and <code>smb://server</code> URLs which do not specify a share,
+ * <code>null</code> will be returned.
+ *
+ * @return  The share component or <code>null</code> if there is no share
+ */
+
+       public String getShare() {
+               return url.share;
+       }
+
+/** 
+ * Retrieve the hostname of the server for this SMB resource. If this
+ * <code>SmbFile</code> references a workgroup, the name of the workgroup
+ * is returned. If this <code>SmbFile</code> refers to the root of this
+ * SMB network hierarchy, <code>null</code> is returned.
+ * 
+ * @return  The server or workgroup name or <code>null</code> if this
+ *          <code>SmbFile</code> refers to the root <code>smb://</code> resource.
+ */ 
+
+       public String getServer() {
+               return url.server;
+       }
+
+/**
+ * Determines wheather or not this resource is a workgroup by querying
+ * the NetBIOS name service. Only a URL of the form <code>smb://name</code>
+ * has the capacity to be a workgroup.
+ *
+ * @return  <code>true</code> if this <code>SmbFile</code> refers to a
+ *          workgroup and <code>false</code> otherwise.
+ */
+
+       public boolean isWorkgroup() {
+               return url.isWorkgroup;
+       }
+
+/**
+ * Tests to see if the SMB resource exists. If the resource refers
+ * only to a server, this method determines if the server exists on the
+ * network and is advertising SMB services. If this resource refers to
+ * a workgroup, this method determines if the workgroup name is valid on
+ * the local SMB network. If this <code>SmbFile</code> refers to the root
+ * <code>smb://</code> resource <code>true</code> is always returned. If
+ * this <code>SmbFile</code> is a traditional file or directory, it will
+ * be queried for on the specified server as expected.
+ *
+ * @return <code>true</code> if the resource exists or is alive or
+ *         <code>false</code> otherwise
+ */
+
+       public boolean exists() {
+               attributes = ATTR_READONLY | ATTR_DIRECTORY;
+               lastModified = 0L;
+               try {
+                       if( url.server == null ) {
+                       } else if( url.share == null ) {
+                               try {
+                                       if( url.isWorkgroup ) {
+                                               NbtAddress.getByName( url.server, 0x1d, null );
+                                       } else {
+                                               NbtAddress.getByName( url.server, 0x20, null );
+                                       }
+                               } catch( UnknownHostException uhe ) {
+                                       return false;
+                               }
+                       } else {
+                               if( url.share.equalsIgnoreCase( "IPC$" )) {
+                                       String[] shares = tree.netShareEnum();
+                                       for( int s = 0; s < shares.length; s++ ) {
+                                               if( shares[s].equalsIgnoreCase( "IPC$" )) {
+                                                       return true;
+                                               }
+                                       }
+                                       return false;
+                               }
+                               if( path.equals( "\\" )) {
+                                       String[] shares = tree.netShareEnum();
+                                       for( int s = 0; s < shares.length; s++ ) {
+                                               if( shares[s].equalsIgnoreCase( url.share )) {
+                                                       return true;
+                                               }
+                                       }
+                                       return false;
+                               }
+
+                               Info info = tree.queryPath( path,
+                                               Trans2QueryPathInformationResponse.SMB_QUERY_FILE_BASIC_INFO );
+                               if( info == null ) {
+                                       return false;
+                               }
+                               attributes = info.getAttributes();
+                               lastModified = info.getLastWriteTime();
+                       }
+                       return true;
+               } catch( Exception e ) {
+                       Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
+               }
+               return false;
+       }
+
+/**
+ * Tests to see if the file this <code>SmbFile</code> represents can be
+ * read. Because any file, directory, or other resource can be read if it
+ * exists, this method simply calls the <code>exists</code> method.
+ *
+ * @return <code>true</code> if the file is read-only
+ */
+
+       public boolean canRead() {
+               return exists();
+       }
+
+/**
+ * Tests to see if the file this <code>SmbFile</code> represents
+ * exists and is not marked read-only. By default, resources are
+ * considered to be read-only and therefore for <code>smb://</code>,
+ * <code>smb://workgroup</code>, and <code>smb://server</code> resources
+ * will be read-only.
+ *
+ * @return  <code>true</code> if the resource exists is not marked
+ *          read-only
+ */
+
+       public boolean canWrite() {
+               if( isPipe ) {
+                       return true;
+               }
+               return exists() && ( attributes & ATTR_READONLY ) == 0;
+       }
+
+/**
+ * Tests to see if the file this <code>SmbFile</code> represents is a directory.
+ *
+ * @return <code>true</code> if this <code>SmbFile</code> is a directory
+ */
+
+       public boolean isDirectory() {
+               return exists() && ( attributes & ATTR_DIRECTORY ) == ATTR_DIRECTORY;
+       }
+
+/**
+ * Tests to see if the file this <code>SmbFile</code> represents is not a directory.
+ *
+ * @return <code>true</code> if this <code>SmbFile</code> is not a directory
+ */
+
+       public boolean isFile() {
+               return exists() && ( attributes & ATTR_DIRECTORY ) == 0;
+       }
+
+/**
+ * Tests to see if the file this SmbFile represents is marked as hidden.
+ *
+ * @return <code>true</code> if the <code>SmbFile</code> is marked as being hidden
+ */
+
+       public boolean isHidden() {
+               if( url.share == null ) {
+                       return false;
+               } else if( path.length() == 1 ) {
+                       if( url.share.endsWith( "$" )) {
+                               return true;
+                       }
+                       return false;
+               }
+               exists();
+               return ( attributes & ATTR_HIDDEN ) == ATTR_HIDDEN;
+       }
+
+/**
+ * Retrieve the last time the file represented by this
+ * <code>SmbFile</code> was modified. The value returned is suitable
+ * for constructing a {@link java.util.Date} object and is adjusted for
+ * the servers timezone differential. Times should be the same as those
+ * reported using the properties dialog of the Windows Explorer program.
+ *
+ * @return The number of milliseconds since the 00:00:00 GMT, January 1,
+ *         1970 as a <code>long</code> value
+ */
+
+       public long lastModified() {
+               exists();
+               return lastModified;
+       }
+
+/**
+ * List the contents of this SMB resource. The list returned by this method will be;
+ *
+ * <ul>
+ * <li> files and directories contained within this resource if the resource is a normal disk file directory,
+ * <li> all available NetBIOS workgroups or domains if this resource is the top level URL <code>smb://</code>,
+ * <li> all servers registered as members of a NetBIOS workgroup if this resource refers to a workgroup in a <code>smb://workgroup</code> URL,
+ * <li> all browseable shares of a server including printers, IPC services, or disk volumes if this resource is a server URL in the form <code>smb://server</code>,
+ * <li> or <code>null</code> if the resource cannot be resolved.
+ * </ul>
+ *
+ * @return A <code>String</code> array of file and directories, workgroups, servers, or shares depending on the context of the resource URL
+ */
+
+       public String[] list() {
+               try {
+                       if( url.server == null ) {
+                               try {
+                                       SmbTree.setLmbTree( this );
+                               } catch( IOException ioe ) {
+                                       Log.printStackTrace(
+                                                               "smb exception contacting local master browser", ioe );
+                                       return null;
+                               }
+                               return tree.domainEnum();
+                       } else if( url.share == null ) {
+                               if( url.isWorkgroup ) {
+                                       return tree.netServerEnum2( url.server );
+                               } else {
+                                       return tree.netShareEnum();
+                               }
+                       }
+                       return tree.find( path );
+               } catch( Exception e ) {
+                       Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
+               }
+               return null;
+       }
+
+/**
+ * Changes the name of the file this <code>SmbFile</code> represents to the name
+ * designated by the <code>SmbFile</code> argument(Remember:
+ * <code>SmbFile</code>s are immutible
+ * and therefore the path associated with this <code>SmbFile</code> object will not
+ * change).
+ *
+ * @param  dest  An <code>SmbFile</code> that represents the new pathname
+ * @return <code>true</code> if the file or directory was successfully renamed
+ * @throws NullPointerException
+ *         If the <code>dest</code> argument is <code>null</code>
+ */
+
+       public boolean renameTo( SmbFile dest ) {
+               try {
+                       if( dest.exists() ) {
+                               // otherwise we get Access Denied
+                               if(( dest.attributes & ATTR_DIRECTORY ) == ATTR_DIRECTORY ) {
+                                       Log.println( Log.WARNINGS, "SmbFile warning",
+                                               " cannot renameTo() a directory that exists: " + dest.getName() );
+                                       return false;
+                               }
+                               if( dest.delete() == false ) {
+                                       return false;
+                               }
+                       }
+                       return tree.rename( path, dest.path );
+               } catch( Exception e ) {
+                       Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
+               }
+               return false;
+       }
+
+/**
+ * This method will delete the file or directory specified by this
+ * <code>SmbFile</code>. If the target is a directory, the contents of
+ * the directory will be deleted as well.
+ *
+ * @return  <code>true</code> if the delete operation was successfull and
+ *          <code>false</code> otherwise
+ */
+
+       public boolean delete() {
+               if( path.length() > 1 ) {
+                       if( exists() ) {
+                               try {
+                                       return tree.delete( path, ( attributes & ATTR_DIRECTORY ) == ATTR_DIRECTORY );
+                               } catch( Exception e ) {
+                                       Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
+                               }
+                       }
+               } else {
+                       Log.println( Log.WARNINGS, "SmbFile warning",
+                                                       " cannot delete servers, workgroups, or shares" );
+               }
+               return false;
+       }
+
+/**
+ * Returns the length in bytes of this file represented by this
+ * <code>SmbFile</code>. The <code>SmbFile</code> must not be a directory.
+ *
+ * @return The length of the file in bytes
+ */
+
+       public long length() {
+               Info info = null;
+               if( path.length() > 1 ) {
+                       try {
+                               int infoLevel =
+                                               Trans2QueryPathInformationResponse.SMB_QUERY_FILE_STANDARD_INFO;
+                               info = tree.queryPath( path, infoLevel );
+                       } catch( Exception e ) {
+                               info = null;
+                               Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
+                       }
+                       if( info != null && ( info.getAttributes() & ATTR_DIRECTORY ) == 0 ) {
+                               // will do long a little later. not hard.
+                               size = info.getSize();
+                               return size;
+                       }
+               }
+               return 0L;
+       }
+
+/**
+ * Creates a directory with the path specified by this
+ * <code>SmbFile</code>. For this method to be successfull, the target
+ * must not already exist. This method will return false when
+ * used with <code>smb://</code>, <code>smb://workgroup</code>,
+ * <code>smb://server</code>, or <code>smb://server/share</code> URLs
+ * because workgroups, servers, and shares cannot be dynamically created.
+ *
+ * @return  <code>true</code> if the file was successfully created or
+ *          <code>false</code> otherwise
+ */
+
+       public boolean mkdir() {
+               if( path.length() > 1 ) {
+                       try {
+                               return tree.createDirectory( path );
+                       } catch( Exception e ) {
+                               Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
+                       }
+               } else {
+                       Log.println( Log.WARNINGS, "SmbFile warning",
+                                               " cannot create servers, workgroups, or shares with mkdir" );
+               }
+               return false;
+       }
+
+/**
+ * Returns a {@link java.net.URL} for this <code>SmbFile</code>. The
+ * <code>URL</code> may be used as any other <code>URL</code> might to
+ * access an smb resource. Currently only retrieving data and information
+ * is supported.
+ *
+ * @return   A new <code>URL</code> for this <code>SmbFile</code>
+ */
+
+       public URL toURL() throws MalformedURLException {
+               return new URL( url.toString() );
+       }
+
+/**
+ * Computes a hashCode for this file based on the URL string and IP
+ * address if the server. The hashing function uses the hashcode of the
+ * server address, the canonical representation of the URL, and does not
+ * compare authentication information. In essance, two
+ * <code>SmbFile</code> objects that refer to
+ * the same file should generate the same hashcode provided it is possible
+ * to make such a determination.
+ *
+ * @return  A hashcode for this abstract file
+ */
+
+       public int hashCode() {
+               if( hash == 0 ) {
+                       hash = address.hashCode();
+                       if( url.port != 0 && url.port != 139 ) {
+                               hash += 65621 * url.port;
+                       }
+                       if( url.share != null ) {
+                               hash += 65521 * url.share.toUpperCase().hashCode();
+                               if( url.canonicalPath != null ) {
+                                       hash += 65521 * url.canonicalPath.toUpperCase().hashCode();
+                               }
+                       }
+               }
+               return hash;
+       }
+
+/**
+ * Tests to see if two <code>SmbFile</code> objects are equal. Two
+ * SmbFile objects are equal when they reference the same SMB
+ * resource. More specifically, two <code>SmbFile</code> objects are
+ * equals if their server IP addresses are equal and the canonicalized
+ * representation of their URLs, minus authentication parameters, are
+ * case insensitivly and lexographically equal. For example, assuming the
+ * server <code>angus</code> resolves to the <code>192.168.1.15</code>
+ * IP address, the below URLs would result in <code>SmbFile</code>s
+ * that are equal.
+ *
+ * <p><blockquote><pre>
+ * smb://192.168.1.15/share/DIR/foo.txt
+ * smb://angus/share/data/../dir/foo.txt
+ * </pre></blockquote>
+ *
+ * @param   obj Another <code>SmbFile</code> object to compare for equality
+ * @return  <code>true</code> if the two objects refer to the same SMB resource
+ *          and <code>false</code> otherwise
+ */
+
+       public boolean equals( Object obj ) {
+               return obj instanceof SmbFile && obj.hashCode() == hashCode();
+       }
+
+/**
+ * Returns the string representation of this SmbFile object. This will
+ * be the same as the URL used to construct this <code>SmbFile</code>. The
+ * path will not be canonicalized. This method will return the same value
+ * as <code>getPath</code>.
+ *
+ * @return  The URL representation of this SMB resource
+ */
+
+       public String toString() {
+               return url.toString();
+       }
+
+}
diff --git a/src/jcifs/smb/SmbFileInputStream.java b/src/jcifs/smb/SmbFileInputStream.java
new file mode 100644 (file)
index 0000000..7913b20
--- /dev/null
@@ -0,0 +1,160 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This InputStream can read bytes from a file on an SMB file server.
+ */
+
+public class SmbFileInputStream extends InputStream {
+
+       private SmbFile file;
+       private int fp, off, readSize, openFlags;
+       private byte[] tmp = new byte[1];
+
+/**
+ * Creates an {@link java.io.InputStream} for reading bytes from a file on
+ * an SMB server addressed by the <code>url</code> parameter. See {@link
+ * jcifs.smb.SmbFile} for a detailed description and examples of the smb
+ * URL syntax.
+ *
+ * @param url An smb URL string representing the file to read from
+ * @return A new <code>InputStream</code> for the specified <code>SmbFile</code>
+ * @throws IOException if a network error occurs
+ */
+
+       public SmbFileInputStream( String url ) throws IOException {
+               this( new SmbFile( url ));
+       }
+
+/**
+ * Creates an {@link java.io.InputStream} for reading bytes from a file on
+ * an SMB server represented by the {@link jcifs.smb.SmbFile} parameter. See
+ * {@link jcifs.smb.SmbFile} for a detailed description and examples of
+ * the smb URL syntax.
+ *
+ * @param url An smb URL string representing the file to write to
+ * @return A new <code>InputStream</code> for the specified <code>SmbFile</code>
+ * @throws IOException if a network error occurs
+ */
+
+       public SmbFileInputStream( SmbFile file ) throws IOException {
+               this( file, SmbFile.O_RDONLY );
+       }
+
+       SmbFileInputStream( SmbFile file, int openFlags ) throws IOException {
+               this.file = file;
+               this.openFlags = openFlags;
+               file.open( openFlags );
+               readSize = Math.min( file.tree.session.transport.rcv_buf_size - 70,
+                                                       file.tree.session.transport.server.maxBufferSize - 70 );
+       }
+
+/**
+ * Closes this input stream and releases any system resources associated with the stream.
+ *
+ * @throws IOException if a network error occurs
+ */
+
+       public void close() throws IOException {
+               file.close();
+       }
+
+/**
+ * Reads a byte of data from this input stream.
+ *
+ * @throws IOException if a network error occurs
+ */
+
+       public int read() throws IOException {
+               // need oplocks to cache otherwise use BufferedInputStream
+               if( read( tmp, 0, 1 ) == -1 ) {
+                       return -1;
+               }
+               return tmp[0] & 0xFF;
+       }
+
+/**
+ * Reads up to b.length bytes of data from this input stream into an array of bytes.
+ *
+ * @throws IOException if a network error occurs
+ */
+
+       public int read( byte[] b ) throws IOException {
+               return read( b, 0, b.length );
+       }
+
+/**
+ * Reads up to len bytes of data from this input stream into an array of bytes.
+ *
+ * @throws IOException if a network error occurs
+ */
+
+       public int read( byte[] b, int off, int len ) throws IOException {
+               if( len <= 0 ) {
+                       return 0;
+               }
+               int start = fp;
+
+               // ensure file is open
+               if( file.isOpen() == false ) {
+                       file.open( openFlags );
+               }
+
+               Log.println( Log.WARNINGS, "smb read warning",
+                               " fid=" + file.fid + ",off=" + off + ",len=" + len );
+
+               /*
+                * Read AndX Request / Response
+                */
+
+               SmbComReadAndXResponse response = new SmbComReadAndXResponse( b, off );
+
+               if( file.isPipe ) {
+                       response.responseTimeout = 0;
+               }
+
+               int r, n;
+               do {
+                       r = len > readSize ? readSize : len;
+//System.out.println( "len=" + len + ",r=" + r + ",fp=" + fp );
+                       try {
+                               file.tree.send( new SmbComReadAndX( file.fid, fp, r, null ), response );
+                       } catch( SmbException se ) {
+                               if( file.isPipe && se.errorClass == SmbException.ERRDOS &&
+                                                                                       se.errorCode == SmbException.ERRbrokenpipe ) {
+                                       return -1;
+                               }
+                               throw se;
+                       }
+                       if(( n = response.dataLength ) <= 0 ) {
+                               return -1;
+                       }
+//System.out.println( "n=" + n );
+                       fp += n;
+                       len -= n;
+                       response.off += n;
+               } while( len > 0 && n == r );
+
+               return fp - start;
+       }
+}
diff --git a/src/jcifs/smb/SmbFileOutputStream.java b/src/jcifs/smb/SmbFileOutputStream.java
new file mode 100644 (file)
index 0000000..f3ec600
--- /dev/null
@@ -0,0 +1,176 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * This <code>OutputStream</code> can write bytes to a file on an SMB file server.
+ */
+
+public class SmbFileOutputStream extends OutputStream {
+
+       private SmbFile file;
+       private boolean append;
+       private int openFlags, fp, writeSize;
+       private byte[] tmp = new byte[1];
+
+/**
+ * Creates an {@link java.io.OutputStream} for writing to a file
+ * on an SMB server addressed by the URL parameter. See {@link
+ * jcifs.smb.SmbFile} for a detailed description and examples of
+ * the smb URL syntax.
+ *
+ * @param url An smb URL string representing the file to write to
+ * @return A new <code>OutputStream</code> for the specified file
+ * @throws IOException if a network error occurs
+ */
+
+       public SmbFileOutputStream( String url ) throws IOException {
+               this( url, false );
+       }
+
+/**
+ * Creates an {@link java.io.OutputStream} for writing bytes to a file on
+ * an SMB server represented by the {@link jcifs.smb.SmbFile} parameter. See
+ * {@link jcifs.smb.SmbFile} for a detailed description and examples of
+ * the smb URL syntax.
+ *
+ * @param url An <code>SmbFile</code> specifying the file to write to
+ * @return A new <code>OutputStream</code> for the specified <code>SmbFile</code>
+ * @throws IOException if a network error occurs
+ */
+
+       public SmbFileOutputStream( SmbFile file ) throws IOException {
+               this( file, false );
+       }
+
+/**
+ * Creates an {@link java.io.OutputStream} for writing bytes to a file on an
+ * SMB server addressed by the URL parameter. See {@link jcifs.smb.SmbFile}
+ * for a detailed description and examples of the smb URL syntax. If the
+ * second argument is <code>true</code>, then bytes will be written to the
+ * end of the file rather than the beginning.
+ *
+ * @param url An smb URL string representing the file to write to
+ * @return A new <code>OutputStream</code> for the specified <code>url</code>
+ * @throws IOException if a network error occurs
+ */
+
+       public SmbFileOutputStream( String url, boolean append ) throws IOException {
+               this( new SmbFile( url ), append );
+       }
+
+/**
+ * Creates an {@link java.io.OutputStream} for writing bytes to a file
+ * on an SMB server addressed by the <code>SmbFile</code> parameter. See
+ * {@link jcifs.smb.SmbFile} for a detailed description and examples of
+ * the smb URL syntax. If the second argument is <code>true</code>, then
+ * bytes will be written to the end of the file rather than the beginning.
+ * 
+ * @param url An <code>SmbFile</code> representing the file to write to
+ * @return A new <code>OutputStream</code> for the specified <code>SmbFile</code>
+ * @throws IOException if a network error occurs
+ */
+
+       public SmbFileOutputStream( SmbFile file, boolean append ) throws IOException {
+               this( file, append, append ? SmbFile.O_CREAT | SmbFile.O_WRONLY | SmbFile.O_APPEND :
+                                                                       SmbFile.O_CREAT | SmbFile.O_WRONLY | SmbFile.O_TRUNC );
+       }
+
+       SmbFileOutputStream( SmbFile file, boolean append, int openFlags ) throws IOException {
+               this.file = file;
+               this.append = append;
+               this.openFlags = openFlags;
+               if( append ) {
+                       fp = (int)file.length();
+               }
+               file.open( openFlags );
+               writeSize = Math.min( file.tree.session.transport.snd_buf_size - 70,
+                                                       file.tree.session.transport.server.maxBufferSize - 70 );
+       }
+
+/**
+ * Closes this output stream and releases any system resources associated
+ * with it.
+ *
+ * @throws IOException if a network error occurs
+ */
+
+       public void close() throws IOException {
+               file.close();
+       }
+
+/**
+ * Writes the specified byte to this file output stream.
+ *
+ * @throws IOException if a network error occurs
+ */
+
+       public void write( int b ) throws IOException {
+               tmp[0] = (byte)b;
+               write( tmp, 0, 1 );
+       }
+
+/**
+ * Writes b.length bytes from the specified byte array to this
+ * file output stream.
+ *
+ * @throws IOException if a network error occurs
+ */
+
+       public void write( byte[] b ) throws IOException {
+               write( b, 0, b.length );
+       }
+
+/**
+ * Writes len bytes from the specified byte array starting at
+ * offset off to this file output stream.
+ *
+ * @param b The array 
+ * @throws IOException if a network error occurs
+ */
+
+       public void write( byte[] b, int off, int len ) throws IOException {
+               if( len <= 0 ) {
+                       return;
+               }
+
+               // ensure file is open
+               if( file.isOpen() == false ) {
+                       file.open( openFlags );
+                       if( append ) {
+                               fp = (int)file.length();
+                       }
+               }
+
+               Log.println( Log.WARNINGS, "smb write warning",
+                                               " fid=" + file.fid + ",off=" + off + ",len=" + len );
+               int w;
+               do {
+                       w = len > writeSize ? writeSize : len;
+                       file.tree.send( new SmbComWriteAndX( file.fid, fp, len - w, b, off, w, null ),
+                                                                                                               new SmbComWriteAndXResponse() );
+                       fp += w;
+                       len -= w;
+                       off += w;
+               } while( len > 0 );
+       }
+}
diff --git a/src/jcifs/smb/SmbNamedPipe.java b/src/jcifs/smb/SmbNamedPipe.java
new file mode 100644 (file)
index 0000000..796aad2
--- /dev/null
@@ -0,0 +1,181 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ *                     "Paul Walker" <Paul.Walker@NBNZ.CO.NZ>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+
+/**
+ * This class will allow a Java program to read and write data to Named
+ * Pipes and Transact NamedPipes.
+ *
+ * <p>There are three Win32 function calls provided by the Windows SDK
+ * that are important in the context of using jCIFS. They are:
+ *
+ * <ul>
+ * <li> <code>CallNamedPipe</code> A message-type pipe call that opens,
+ *      writes to, reads from, and closes the pipe in a single operation.
+ * <li> <code>TransactNamedPipe</code> A message-type pipe call that
+ *      writes to and reads from an existing pipe descriptor in one operation.
+ * <li> <code>CreateFile</code>, <code>ReadFile</code>,
+ *      <code>WriteFile</code>, and <code>CloseFile</code> A byte-type pipe can
+ *      be opened, written to, read from and closed using the standard Win32
+ *      file operations.
+ * </ul>
+ *
+ * <p>The jCIFS API maps all of these operations into the standard Java
+ * <code>XxxputStream</code> interface. A special <code>PIPE_TYPE</code>
+ * flags is necessary to distinguish which type of Named Pipe behavior
+ * is desired.
+ *
+ * <p><table border="1" cellpadding="3" cellspacing="0" width="100%">
+ * <tr bgcolor="#ccccff">
+ * <td colspan="2"><b><code>SmbNamedPipe</code> Constructor Examples</b></td>
+ * <tr><td width="20%"><b>Code Sample</b></td><td><b>Description</b></td></tr>
+ * <tr><td width="20%"><pre>
+ * new SmbNamedPipe( "smb://server/IPC$/PIPE/foo",
+ *         SmbNamedPipe.PIPE_TYPE_RDWR |
+ *         SmbNamedPipe.PIPE_TYPE_CALL );
+ * </pre></td><td>
+ * Open the Named Pipe foo for reading and writing. The pipe will behave like the <code>CallNamedPipe</code> interface.
+ * </td></tr>
+ * <tr><td width="20%"><pre>
+ * new SmbNamedPipe( "smb://server/IPC$/foo",
+ *         SmbNamedPipe.PIPE_TYPE_RDWR |
+ *         SmbNamedPipe.PIPE_TYPE_TRANSACT );
+ * </pre></td><td>
+ * Open the Named Pipe foo for reading and writing. The pipe will behave like the <code>TransactNamedPipe</code> interface.
+ * </td></tr>
+ * <tr><td width="20%"><pre>
+ * new SmbNamedPipe( "smb://server/IPC$/foo",
+ *         SmbNamedPipe.PIPE_TYPE_RDWR );
+ * </pre></td><td>
+ * Open the Named Pipe foo for reading and writing. The pipe will
+ * behave as though the <code>CreateFile</code>, <code>ReadFile</code>,
+ * <code>WriteFile</code>, and <code>CloseFile</code> interface was
+ * being used.
+ * </td></tr>
+ * </table>
+ *
+ * <p>See <a href="../../../pipes.html">Using jCIFS to Connect to Win32
+ * Named Pipes</a> for a detailed description of how to use jCIFS with
+ * Win32 Named Pipe server processes.
+ *
+ * @since    jcifs-0.5
+ */
+
+public class SmbNamedPipe extends SmbFile {
+
+       /**
+        * The pipe should be opened read-only.
+        */
+
+       public static final int PIPE_TYPE_RDONLY = O_RDONLY;
+
+       /**
+        * The pipe should be opened only for writing.
+        */
+
+       public static final int PIPE_TYPE_WRONLY = O_WRONLY;
+
+       /**
+        * The pipe should be opened for both reading and writing.
+        */
+
+       public static final int PIPE_TYPE_RDWR   = O_RDWR;
+
+       /**
+        * Pipe operations should behave like the <code>CallNamedPipe</code> Win32 Named Pipe function.
+        */
+
+       public static final int PIPE_TYPE_CALL   = 0x01;
+
+       /**
+        * Pipe operations should behave like the <code>TransactNamedPipe</code> Win32 Named Pipe function.
+        */
+
+       public static final int PIPE_TYPE_TRANSACT = 0x02;
+
+       InputStream pipeIn;
+       OutputStream pipeOut;
+       int pipeType;
+
+       /**
+        * Open the Named Pipe resource specified by the url
+        * parameter. The pipeType parameter should be at least one of
+        * the <code>PIPE_TYPE</code> flags combined with the bitwise OR
+        * operator <code>|</code>. See the examples listed above.
+        */
+
+       public SmbNamedPipe( String url, int pipeType )
+                                                       throws MalformedURLException, UnknownHostException {
+               super( url );
+               this.pipeType = pipeType;
+               isPipe = true;
+       }
+
+       /**
+        * Return the <code>InputStream</code> used to read information
+        * from this pipe instance. Presumably data would first be written
+        * to the <code>OutputStream</code> associated with this Named
+        * Pipe instance although this is not a requirement (e.g. a
+        * read-only named pipe would write data to this stream on
+        * connection). Reading from this stream may block. Therefore it
+        * may be necessary that an addition thread be used to read and
+        * write to a Named Pipe.
+        */
+
+       public InputStream getNamedPipeInputStream() throws IOException {
+               if( pipeIn == null ) {
+                       if(( pipeType & PIPE_TYPE_CALL ) == PIPE_TYPE_CALL ||
+                                       ( pipeType & PIPE_TYPE_TRANSACT ) == PIPE_TYPE_TRANSACT ) {
+                               pipeIn = new TransactNamedPipeInputStream();
+                       } else {
+                               pipeIn = new SmbFileInputStream( this,
+                                                                                       ( pipeType & 0xFF0000 ) | SmbFile.O_EXCL );
+                       }
+               }
+               return pipeIn;
+       }
+
+       /**
+        * Return the <code>OutputStream</code> used to write
+        * information to this pipe instance. The act of writing data
+        * to this stream will result in response data recieved in the
+        * <code>InputStream</code> associated with this Named Pipe
+        * instance (unless of course it does not elicite a response or the pipe is write-only).
+        */
+
+       public OutputStream getNamedPipeOutputStream() throws IOException {
+               if( pipeOut == null ) {
+                       if(( pipeType & PIPE_TYPE_CALL ) == PIPE_TYPE_CALL ||
+                                       ( pipeType & PIPE_TYPE_TRANSACT ) == PIPE_TYPE_TRANSACT ) {
+                               pipeOut = new TransactNamedPipeOutputStream( this );
+                       } else {
+                               pipeOut = new SmbFileOutputStream( this, false,
+                                                                                       ( pipeType & 0xFF0000 ) | SmbFile.O_EXCL );
+                       }
+               }
+               return pipeOut;
+       }
+}
diff --git a/src/jcifs/smb/SmbSession.java b/src/jcifs/smb/SmbSession.java
new file mode 100644 (file)
index 0000000..1923944
--- /dev/null
@@ -0,0 +1,188 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.netbios.NbtAddress;
+import jcifs.util.DES;
+import jcifs.util.MD4;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.net.InetAddress;
+
+class SmbSession {
+
+    // KGS!@#$%
+    static final byte[] S8 = {
+               (byte)0x4b, (byte)0x47, (byte)0x53, (byte)0x21,
+               (byte)0x40, (byte)0x23, (byte)0x24, (byte)0x25
+       };
+       static void E( byte[] key, byte[] data, byte[] e ) {
+               byte[] key7 = new byte[7];
+               byte[] e8 = new byte[8];
+
+               for( int i = 0; i < key.length / 7; i++ ) {
+                       System.arraycopy( key, i * 7, key7, 0, 7 );
+                       DES des = new DES( key7 );
+                       des.encrypt( data, e8 );
+                       System.arraycopy( e8, 0, e, i * 8, 8 );
+               }
+       }
+       static byte[] getPreNTLMResponse( String password, byte[] challenge ) {
+               byte[] p14 = new byte[14];
+        byte[] p21 = new byte[21];
+        byte[] p24 = new byte[24];
+
+        System.arraycopy( password.toUpperCase().getBytes(), 0, p14, 0, password.length() );
+        E( p14, S8, p21);
+               E( p21, challenge, p24);
+        return p24;
+       }
+       static byte[] getNTLMResponse( String password, byte[] challenge ) {
+               byte[] uni = null;
+               byte[] p21 = new byte[21];
+               byte[] p24 = new byte[24];
+
+               try {
+                       uni = password.getBytes( "UnicodeLittleUnmarked" );
+               } catch( UnsupportedEncodingException uee ) {
+                       Log.printStackTrace( "password encryption exception", uee );
+               }
+               MD4 md4 = new MD4();
+               md4.update( uni );
+               System.arraycopy( md4.digest(), 0, p21, 0, 16 );
+               E( p21, challenge, p24 );
+               return p24;
+       }
+
+       int uid;
+       String username, password, domain;
+       SmbTransport transport;
+       Vector trees;
+       boolean sessionSetup;
+       String passwordString = "*****";
+
+       SmbSession( SmbTransport transport, String username,
+                                                               String password, String domain ) {
+               this.transport = transport;
+               this.username = username.toUpperCase();
+               this.password = password;
+               this.domain = domain.toUpperCase();
+               trees = new Vector();
+               sessionSetup = false;
+
+               if( password == null ) {
+                       passwordString = "null";
+               } else if( password.length() == 0 ) {
+                       passwordString = "";
+               }
+       }
+
+       synchronized SmbTree getSmbTree( String path, String service ) {
+               SmbTree t;
+               for( Enumeration e = trees.elements(); e.hasMoreElements(); ) {
+                       t = (SmbTree)e.nextElement();
+                       if( t.matches( path, service )) {
+                               return t;
+                       }
+               }
+               t = new SmbTree( this, path, service );
+               trees.addElement( t );
+               return t;
+       }
+       boolean matches( String username, String password, String domain ) {
+               return this.username.equals( username.toUpperCase() ) &&
+                               this.password.equals( password ) &&
+                               this.domain.equals( domain.toUpperCase() );
+       }
+       void sendTransaction( SmbComTransaction request,
+                                                               SmbComTransactionResponse response ) throws IOException {
+               // transactions are not batchable
+               sessionSetup( null, null );
+               request.uid = uid;
+               transport.sendTransaction( request, response );
+       }
+       void send( ServerMessageBlock request,
+                                                               ServerMessageBlock response ) throws IOException {
+               if( response != null ) {
+                       response.received = false;
+               }
+               sessionSetup( request, response );
+               if( response != null && response.received ) {
+                       return;
+               }
+               request.uid = uid;
+               transport.send( request, response );
+       }
+       synchronized void sessionSetup( ServerMessageBlock andx,
+                                                               ServerMessageBlock andxResponse )
+                                                               throws IOException {
+
+               if( sessionSetup ) {
+                       return;
+               }
+
+               Log.println( Log.WARNINGS, "smb session setup warning",
+                                       " requesting session with accountName=" + username +
+                                       ",accountPassword=" + passwordString +
+                                       ",primaryDomain=" + domain );
+
+               /*
+                * Session Setup And X Request / Response
+                */
+
+               SmbComSessionSetupAndXResponse response =
+                                                               new SmbComSessionSetupAndXResponse( andxResponse );
+               transport.send( new SmbComSessionSetupAndX( this, andx ), response );
+
+               uid = response.uid;
+               sessionSetup = true;
+       }
+       synchronized void logoff() throws IOException {
+               if( sessionSetup == false ) {
+                       return;
+               }
+
+               for( Enumeration e = trees.elements(); e.hasMoreElements(); ) {
+                       SmbTree t = (SmbTree)e.nextElement();
+                       t.treeDisconnect();
+               }
+               sessionSetup = false;
+
+               if( transport.server.security == ServerMessageBlock.SECURITY_SHARE ) {
+                       return;
+               }
+
+               /*
+                * Logoff And X Request / Response
+                */
+
+               SmbComLogoffAndX request = new SmbComLogoffAndX( null );
+               request.uid = uid;
+               transport.send( request, null );
+       }
+       public String toString() {
+               return "SmbSession[accountName=" + username +
+                               ",accountPassword=" + passwordString +
+                               ",primaryDomain=" + domain +
+                               ",uid=" + uid + "]";
+       }
+}
diff --git a/src/jcifs/smb/SmbTransport.java b/src/jcifs/smb/SmbTransport.java
new file mode 100644 (file)
index 0000000..a1dc22f
--- /dev/null
@@ -0,0 +1,666 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.netbios.NbtSocket;
+import jcifs.netbios.NbtException;
+import jcifs.netbios.NbtAddress;
+import jcifs.Config;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PushbackInputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+class SmbTransport implements Runnable {
+
+       private static final int DEFAULT_MAX_MPX_COUNT = 10;
+       private static final int DEFAULT_RESPONSE_TIMEOUT = 10000;
+       private static final int DEFAULT_SO_TIMEOUT    = 15000;
+       private static final int PUSHBACK_BUF_SIZE     = 64;
+       private static final int DEFAULT_RCV_BUF_SIZE  = 4096;
+       private static final int DEFAULT_SND_BUF_SIZE  = 1300;
+
+       static final int MID_OFFSET      = 30;
+       static final int HEADER_LENGTH   = 32;
+       static final int FLAGS_OFFSET    = 9;
+       static final int FLAGS_RESPONSE  = 0x80;
+
+       private byte[] rcv_buf, snd_buf;
+
+       private NbtSocket socket;
+       private InputStream in;
+       private OutputStream out;
+       private int localPort, soTimeout, responseTimeout;
+       private long closeTime;
+       private InetAddress localAddr;
+       private Hashtable responseTable;
+       private Thread thread;
+       private Object outLock;
+
+       private static Vector connections = new Vector();
+       private static MpxControl mpxCtrl = new MpxControl();
+
+       Vector sessions;
+       boolean negotiated, useUnicode;
+
+       NbtAddress address;
+       int port, rcv_buf_size, snd_buf_size;
+
+       int negotiatedDialectIndex;
+       int negotiatedMaxMpxCount;
+       int negotiatedMaxBufferSize;
+       int negotiatedCapabilities;
+
+       ClientProperties client = new ClientProperties();
+       ServerProperties server = new ServerProperties();
+
+       class ClientProperties {
+               int maxMpxCount = Config.getInt( "jcifs.smb.client.maxMpxCount",
+                                                                                                       DEFAULT_MAX_MPX_COUNT );
+               int maxBufferSize = Config.getInt( "jcifs.smb.client.snd_buf_size",
+                                                                                                       DEFAULT_SND_BUF_SIZE );
+               int sessionKey = 0x00000000;
+               /* NT 4 Workstation client capabilities 0x00D4
+                * we don't do NT Status Codes or Level II oplocks
+                * but we could do raw and mpx
+                */
+               int flags2 = Config.getInt( "jcifs.smb.client.flags2",
+                               ServerMessageBlock.FLAGS2_LONG_FILENAMES |
+                                                                                                       ServerMessageBlock.FLAGS2_UNICODE );
+               int capabilities = Config.getInt( "jcifs.smb.client.capabilities",
+                               ServerMessageBlock.CAP_UNICODE | ServerMessageBlock.CAP_NT_SMBS );
+               String nativeOs = Config.getProperty( "jcifs.smb.client.nativeOs",
+                               System.getProperty( "os.name" ));
+               String nativeLanMan = Config.getProperty( "jcifs.smb.client.nativeLanMan", "foo" );
+               int vcNumber = 1;
+       }
+       class ServerProperties {
+               byte flags;
+               int flags2;
+               int maxMpxCount;
+               int maxBufferSize;
+               int sessionKey;
+               // NT 4 Workstation is 0x43FD
+               int capabilities;
+               String oemDomainName;
+               String primaryDomain;
+               String nativeOs;
+               String nativeLanMan;
+
+               int securityMode;
+               int security;
+               boolean encryptedPasswords;
+               boolean signaturesEnabled;
+               boolean signaturesRequired;
+               int maxNumberVcs;
+               int maxRawSize;
+               long serverTime;
+               int serverTimeZone;
+               int encryptionKeyLength;
+               byte[] encryptionKey;
+       }
+
+       static synchronized SmbTransport getSmbTransport( NbtAddress address, int port ) {
+               return getSmbTransport( address, port,
+                                                       Config.getInetAddress( "jcifs.smb.client.laddr", null ),
+                                                       Config.getInt( "jcifs.smb.client.lport", 0 ));
+       }
+       static synchronized SmbTransport getSmbTransport( NbtAddress address, int port,
+                                                                       InetAddress localAddr, int localPort ) {
+               SmbTransport conn;
+               for( Enumeration e = connections.elements(); e.hasMoreElements(); ) {
+                       conn = (SmbTransport)e.nextElement();
+                       if( conn.matches( address, port, localAddr, localPort )) {
+                               return conn;
+                       }
+               }
+               conn = new SmbTransport( address, port, localAddr, localPort );
+               connections.addElement( conn );
+               return conn;
+       }
+
+       SmbTransport( NbtAddress address, int port, InetAddress localAddr, int localPort ) {
+               this.address = address;
+               this.port = port;
+               this.localAddr = localAddr;
+               this.localPort = localPort;
+
+               useUnicode = Config.getBoolean( "jcifs.smb.client.useUnicode", true );
+               if( useUnicode == false ) {
+                       client.flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_UNICODE;
+                       client.capabilities &= 0xFFFF ^ ServerMessageBlock.CAP_UNICODE;
+               }
+               if( Config.getBoolean( "jcifs.smb.client.useNTSmbs", false ) == true ) {
+                       client.capabilities |= ServerMessageBlock.CAP_NT_SMBS;
+               }
+
+               soTimeout = Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_TIMEOUT );
+               responseTimeout = Config.getInt( "jcifs.smb.client.responseTimeout",
+                                                                                                                       DEFAULT_RESPONSE_TIMEOUT );
+               rcv_buf_size = Config.getInt( "jcifs.smb.client.rcv_buf_size", DEFAULT_RCV_BUF_SIZE );
+               snd_buf_size = client.maxBufferSize;
+               rcv_buf = new byte[rcv_buf_size];
+               snd_buf = new byte[snd_buf_size];
+               sessions = new Vector();
+               responseTable = new Hashtable();
+               outLock = new Object();
+               negotiated = false;
+       }
+
+       synchronized SmbSession getSmbSession() {
+               return getSmbSession( null, null, null );
+       }
+       synchronized SmbSession getSmbSession( String username, String password, String domain ) {
+               if( username == null ) {
+                       username = Config.getProperty( "jcifs.smb.client.username", "guest" );
+               }
+               if( password == null ) {
+                       password = Config.getProperty( "jcifs.smb.client.password", "" );
+               }
+               if( domain == null ) {
+                       domain = Config.getProperty( "jcifs.smb.client.domain", "?" );
+               }
+               SmbSession ssn;
+               for( Enumeration e = sessions.elements(); e.hasMoreElements(); ) {
+                       ssn = (SmbSession)e.nextElement();
+                       if( ssn.matches( username, password, domain )) {
+                               return ssn;
+                       }
+               }
+               ssn = new SmbSession( this, username, password, domain );
+               sessions.addElement( ssn );
+               return ssn;
+       }
+       boolean matches( NbtAddress address, int port, InetAddress localAddr, int localPort ) {
+               InetAddress defaultLocal = null;
+               try {
+                       defaultLocal = InetAddress.getLocalHost();
+               } catch( UnknownHostException uhe ) {
+               }
+               int p1 = ( port == 0 || port == 139 ) ? 0 : port;
+               int p2 = ( this.port == 0 || this.port == 139 ) ? 0 : this.port;
+               InetAddress la1 = localAddr == null ? defaultLocal : localAddr;
+               InetAddress la2 = this.localAddr == null ? defaultLocal : this.localAddr;
+               return address.equals( this.address ) &&
+                                       p1 == p2 &&
+                                       la1.equals( la2 ) &&
+                                       localPort == this.localPort;
+       }
+       void ensureOpen() throws IOException {
+               if( socket == null ) {
+                       try {
+                               socket = new NbtSocket( address, port, localAddr, localPort );
+                       } catch( NbtException ne ) {
+                               if( ne.errorClass == NbtException.ERR_SSN_SRVC &&
+                                                               ( ne.errorCode == NbtException.CALLED_NOT_PRESENT ||
+                                                               ne.errorCode == NbtException.NOT_LISTENING_CALLED )) {
+                                       Log.println( Log.WARNINGS, "smb warning",
+                                                               " failed to establish netbios session: called name not " +
+                                                               "present or not listening for called name, trying " +
+                                                               "*SMBSERVER" );
+                                       socket = new NbtSocket( address, NbtAddress.SMBSERVER_NAME,
+                                                                                                               port, localAddr, localPort );
+                               } else {
+                                       throw ne;
+                               }
+                       }
+                       if( Config.getBoolean( "jcifs.smb.client.tcpNoDelay", false )) {
+                               socket.setTcpNoDelay( true );
+                       }
+                       in = new PushbackInputStream( socket.getInputStream(), PUSHBACK_BUF_SIZE );
+                       out = socket.getOutputStream();
+                       thread = new Thread( this );
+                       thread.setDaemon( true );
+                       thread.start();
+               }
+       }
+       void tryClose() {
+               synchronized( outLock ) {
+                       if( socket != null ) {
+                               try {
+                                       for( Enumeration e = sessions.elements(); e.hasMoreElements(); ) {
+                                               ((SmbSession)e.nextElement()).logoff();
+                                       }
+                                       socket.close();
+                               } catch( IOException ioe ) {
+                               }
+                       }
+                       in = null;
+                       out = null;
+                       socket = null;
+                       negotiated = false;
+                       thread = null;
+                       responseTable.clear();
+               }
+       }
+       public void run() {
+               int mid, l, b, n;
+               ServerMessageBlock response;
+
+               while( thread == Thread.currentThread() ) {
+                       try {
+                               socket.setSoTimeout( soTimeout );
+
+                               if(( b = in.read() ) == -1) {
+                                       break;
+                               }
+                               if(( b & 0xFF ) != 0xFF ) {
+                                       continue;
+                               }
+                               rcv_buf[0] = (byte)0xFF;
+
+                               if( in.read( rcv_buf, 1, HEADER_LENGTH - 1 ) != HEADER_LENGTH - 1 ) {
+                                       /* Read on a netbios SocketInputStream does not
+                                        * return until len bytes have been read or the stream is
+                                        * closed. This must be the latter case.
+                                        */
+                                       break;
+                               }
+                               ((PushbackInputStream)in).unread( rcv_buf, 0, HEADER_LENGTH );
+                               if( rcv_buf[0] != (byte)0xFF ||
+                                                               rcv_buf[1] != (byte)'S' ||
+                                                               rcv_buf[2] != (byte)'M' ||
+                                                               rcv_buf[3] != (byte)'B' ) {
+                                       Log.println( Log.WARNINGS, "smb warning",
+                                                                                               "bad smb header, purging session message" );
+                                       in.skip( in.available() );
+                                       continue;
+                               }
+                               if(( rcv_buf[FLAGS_OFFSET] & FLAGS_RESPONSE ) == FLAGS_RESPONSE ) {
+                                       mid = ServerMessageBlock.readInt2( rcv_buf, MID_OFFSET );
+
+                                       response = (ServerMessageBlock)responseTable.get( new Integer( mid ));
+                                       if( response == null ) {
+                                               Log.println( Log.WARNINGS, "smb warning",
+                                                               " no handler for mid=" + mid + ", purging session message" );
+                                               in.skip( in.available() );
+                                               continue;
+                                       }
+                                       synchronized( response ) {
+                                               response.useUnicode = useUnicode;
+                                               Log.println( Log.DEBUGGING, "smb debugging",
+                                                                                                               " new data read from socket" );
+
+                                               if( response instanceof SmbComTransactionResponse ) {
+                                                       Enumeration e = (Enumeration)response;
+                                                       if( e.hasMoreElements() ) {
+                                                               e.nextElement();
+                                                       } else {
+                                                               Log.println( Log.WARNINGS, "smb warning",
+                                                                                       "more responses to transaction than expected" );
+                                                               continue;
+                                                       }
+                                                       response.readWireFormat( in, rcv_buf, 0 );
+                                                       response.received = true;
+                                                       Log.printMessageData( "smb received", response );
+
+                                                       if( response.errorCode != 0 || e.hasMoreElements() == false ) {
+                                                               ((SmbComTransactionResponse)response).hasMore = false;
+                                                               response.notify();
+                                                       } else {
+                                                               ensureOpen();
+                                                       }
+                                               } else {
+                                                       response.readWireFormat( in, rcv_buf, 0 );
+                                                       response.received = true;
+
+                                                       Log.printMessageData( "smb received", response );
+                                                       ServerMessageBlock smb = response;
+                                                       while( smb instanceof AndXServerMessageBlock &&
+                                                                       ( smb = ((AndXServerMessageBlock)smb).andx ) != null ) {
+                                                               Log.printMessageData( "smb andx data", smb );
+                                                       }
+                                                       Log.printHexDump( "smb received", rcv_buf, 0, response.length );
+
+                                                       response.notify();
+                                               }
+                                       }
+                               } else {
+                                       // it's a request(break oplock)
+                               }
+                       } catch( InterruptedIOException iioe ) {
+                               if( responseTable.size() == 0 ) {
+                                       tryClose();
+                               } else {
+                                       Log.println( Log.WARNINGS, "smb warning",
+                                                               " soTimeout has occured but there are " +
+                                                               responseTable.size() + " pending requests" );
+                               }
+                       } catch( IOException ioe ) {
+                               Log.printStackTrace( "exception reading from socket input", ioe );
+                               tryClose();
+                       }
+               }
+       }
+       void send( ServerMessageBlock request,
+                                                       ServerMessageBlock response ) throws IOException {
+               Integer mid = null;
+
+               negotiate();
+
+               request.flags2 = client.flags2;
+               request.mid = aquireMid();
+               request.useUnicode = useUnicode;
+
+               if( response == null ) {
+                       try {
+                               synchronized( outLock ) {
+                                       ensureOpen();
+                                       out.write( snd_buf, 0, request.writeWireFormat( snd_buf, 0 ));
+                                       out.flush();
+
+                                       Log.printMessageData( "smb sent", request );
+                                       ServerMessageBlock smb = request;
+                                       while( smb instanceof AndXServerMessageBlock &&
+                                                                       ( smb = ((AndXServerMessageBlock)smb).andx ) != null ) {
+                                               Log.printMessageData( "smb andx data", smb );
+                                       }
+                                       Log.printHexDump( "smb sent", snd_buf, 0, request.length );
+                               }
+                       } finally {
+                               releaseMid( request.mid );
+                       }
+
+                       return;
+               }
+
+               // now for the normal case where response is not null
+
+               try {
+                       synchronized( response ) {
+
+                               response.received = false;
+                               mid = new Integer( request.mid );
+                               responseTable.put( mid, response );
+
+                               synchronized( outLock ) {
+                                       ensureOpen();
+                                       out.write( snd_buf, 0, request.writeWireFormat( snd_buf, 0 ));
+                                       out.flush();
+
+                                       Log.printMessageData( "smb sent", request );
+                                       ServerMessageBlock smb = request;
+                                       while( smb instanceof AndXServerMessageBlock &&
+                                                                       ( smb = ((AndXServerMessageBlock)smb).andx ) != null ) {
+                                               Log.printMessageData( "smb andx data", smb );
+                                       }
+                                       Log.printHexDump( "smb sent", snd_buf, 0, request.length );
+                               }
+
+                               // default it 1 so that 0 can be used as forever
+                               response.wait( response.responseTimeout == 1 ?
+                                                                                               responseTimeout : response.responseTimeout );
+                       }
+               } catch( InterruptedException ie ) {
+               } finally {
+                       responseTable.remove( mid );
+                       releaseMid( request.mid );
+               }
+
+               if( response.received == false ) {
+                       throw new IOException(
+                                                       "time out waiting for response from server: " + address );
+               }
+               if( response.errorCode != 0 ) {
+                       throw new SmbException( response.errorCode );
+               }
+       }
+       void sendTransaction( SmbComTransaction request,
+                                                       SmbComTransactionResponse response ) throws IOException {
+               Integer mid = null;
+
+               negotiate();
+
+               try {
+                       request.flags2 = client.flags2;
+                       request.mid = aquireMid();
+                       mid = new Integer( request.mid );
+                       request.useUnicode = useUnicode;
+                       request.maxBufferSize = negotiatedMaxBufferSize;
+                       response.received = false;
+                       response.hasMore = true;
+                       response.isPrimary = true;
+
+                       request.nextElement();
+                       if( request.hasMoreElements() ) {
+                               // multi-part request
+
+                               SmbComBlankResponse interimResponse = new SmbComBlankResponse();
+                               synchronized( interimResponse ) {
+                                       responseTable.put( mid, interimResponse );
+                                       synchronized( outLock ) {
+                                               ensureOpen();
+                                               out.write( snd_buf, 0, request.writeWireFormat( snd_buf, 0 ));
+                                               out.flush();
+
+                                               Log.printMessageData( "smb sent", request );
+                                               Log.printHexDump( "smb sent", snd_buf, 0, request.length );
+                                       }
+                                       interimResponse.wait( responseTimeout );
+
+                                       if( interimResponse.received == false ) {
+                                               throw new IOException( "time out waiting for response from server" );
+                                       }
+                                       if( interimResponse.errorCode != 0 ) {
+                                               throw new SmbException( interimResponse.errorCode );
+                                       }
+                               }
+                               request.nextElement();
+                       }
+
+                       synchronized( response ) {
+                               responseTable.put( mid, response );
+                               do {
+                                       synchronized( outLock ) {
+                                               ensureOpen();
+                                               out.write( snd_buf, 0, request.writeWireFormat( snd_buf, 0 ));
+                                               out.flush();
+
+                                               Log.printMessageData( "smb sent", request );
+                                               Log.printHexDump( "smb sent", snd_buf, 0, request.length );
+                                       }
+                               } while( request.hasMoreElements() && request.nextElement() != null );
+
+                               do {
+                                       // default it 1 so that 0 can be used as forever
+                                       response.wait( response.responseTimeout == 1 ? responseTimeout : response.responseTimeout );
+                               } while( response.received && response.hasMoreElements() );
+                       }
+               } catch( InterruptedException ie ) {
+               } finally {
+                       responseTable.remove( mid );
+                       releaseMid( request.mid );
+               }
+
+               if( response.received == false ) {
+                       throw new IOException( "time out waiting for response from server" );
+               }
+               if( response.errorCode != 0 ) {
+                       throw new SmbException( response.errorCode );
+               }
+       }
+       synchronized void negotiate() throws IOException {
+
+               if( negotiated ) {
+                       return;
+               }
+               /* we must set this here rather than later because this
+                * calls send which calls negotiate so we don't want to
+                * end up in a loop. The alternative would be to inline
+                * the send routine here but this seems okay for now
+                */
+               negotiated = true;
+
+               Log.println( Log.WARNINGS, "smb negotiation warning",
+                                                       " requesting negotiation with " + address );
+
+               /*
+                * Negotiate Protocol Request / Response
+                */
+
+               SmbComNegotiateResponse response = new SmbComNegotiateResponse();
+               send( new SmbComNegotiate(), response );
+
+               if( response.dialectIndex > 10 ) {
+                       throw new IOException( "smb failed to negotiate dialect" );
+               }
+
+               server.securityMode        = response.securityMode;
+               server.security            = response.security;
+               server.encryptedPasswords  = response.encryptedPasswords;
+               server.signaturesEnabled   = response.signaturesEnabled;
+               server.signaturesRequired  = response.signaturesRequired;
+               negotiatedDialectIndex     = response.dialectIndex;;
+               server.maxMpxCount         = response.maxMpxCount;
+               negotiatedMaxMpxCount      = client.maxMpxCount < server.maxMpxCount ?
+                                                                               client.maxMpxCount : server.maxMpxCount;
+               mpxCtrl.maxMpxCount        = negotiatedMaxMpxCount < 1 ?
+                                                                               1 : negotiatedMaxMpxCount;
+               server.maxNumberVcs        = response.maxNumberVcs;
+               server.maxBufferSize       = response.maxBufferSize;
+               negotiatedMaxBufferSize    = client.maxBufferSize < server.maxBufferSize ?
+                                                                               client.maxBufferSize : server.maxBufferSize;
+               server.maxRawSize          = response.maxRawSize;
+               server.sessionKey          = response.sessionKey;
+               server.capabilities        = response.capabilities;
+               negotiatedCapabilities     = client.capabilities & server.capabilities;
+               if(( negotiatedCapabilities & ServerMessageBlock.CAP_UNICODE ) == 0 ) {
+                       // server doesn't want unicode
+                       if( Config.getBoolean( "jcifs.smb.client.useUnicode", false )) {
+                               // force unicode
+                               negotiatedCapabilities |= ServerMessageBlock.CAP_UNICODE;
+                       } else {
+                               // not explicitly set to true so flip unicode off as server requests
+                               useUnicode = false;
+                               client.flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_UNICODE;
+                       }
+               }
+               server.serverTime          = response.serverTime;
+               server.serverTimeZone      = response.serverTimeZone;
+               server.encryptionKeyLength = response.encryptionKeyLength;
+               server.encryptionKey       = response.encryptionKey;
+               server.oemDomainName       = response.oemDomainName;
+       }
+       public String toString() {
+               return "SmbTransport[address=" + address +
+                       ",port=" + socket.getPort() +
+                       ",localAddr=" + socket.getLocalAddress() +
+                       ",localPort=" + socket.getLocalPort() + "]";
+       }
+
+       static int aquireMid() throws IOException {
+               try {
+                       return mpxCtrl.aquireMid();
+               } catch( InterruptedException ie ) {
+                       throw new IOException( ie.getMessage() );
+               }
+       }
+       static void releaseMid( int mid ) {
+               mpxCtrl.releaseMid( mid );
+       }
+
+    static class MpxControl {
+               MpxListNode first, last;
+        class MpxListNode {
+            int i;  
+            MpxListNode next;
+                       MpxListNode( int id ) {
+                               i = id;
+                               next = null;
+                       }
+        }       
+               int nextMid, mpxCount, maxMpxCount;
+
+               MpxControl() {
+                       nextMid = 0;
+                       mpxCount = 0;
+                       maxMpxCount = 1;
+                       first = last = null;
+               }
+
+               synchronized void clear() {
+                       nextMid = 0;
+                       mpxCount = 0;
+                       maxMpxCount = 1;
+                       first = last = null;
+               }
+               synchronized int aquireMid() throws InterruptedException {
+                       while( mpxCount >= maxMpxCount ) {
+                               wait();
+                       }
+                       if(( ++nextMid % 0xFFFF ) == 0 ) {
+                               nextMid = 1;
+                       }
+                       add( nextMid );
+                       mpxCount++;
+                       return nextMid;
+               }
+               synchronized void releaseMid( int i ) {
+                       remove( i );
+                       mpxCount--;
+                       notify();
+               }
+        synchronized boolean contains( int i ) {
+                       for( MpxListNode tmp = first; tmp != null; tmp = tmp.next ) {
+                               if( tmp.i == i ) {
+                                       return true;
+                               }
+                       }
+                       return false;
+        }       
+        synchronized void add( int i ) {
+                       if( contains( i )) {
+                               return;
+                       }
+                       if( first == null ) {
+                               first = last = new MpxListNode( i );
+                       } else {
+                               last = last.next = new MpxListNode( i );
+                       }
+        }
+        synchronized void remove( int i ) {
+                       if( first == null ) {
+                               return;
+                       } else if( first == last && first.i == i ) {
+                               first = last = null;
+                               return;
+                       }
+                       MpxListNode tmp, prev;
+                       for( tmp = prev = first; tmp != null; tmp = tmp.next ) {
+                               if( tmp.i == i ) {
+                                       if( tmp == first ) {
+                                               first = first.next;
+                                       }
+                                       if( tmp == last ) {
+                                               last = prev;
+                                               last.next = null;
+                                       }
+                               }
+                               prev = tmp;
+                       }
+        }       
+    }
+}
diff --git a/src/jcifs/smb/SmbTree.java b/src/jcifs/smb/SmbTree.java
new file mode 100644 (file)
index 0000000..980c250
--- /dev/null
@@ -0,0 +1,502 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.IOException;
+import jcifs.netbios.NbtAddress;
+import java.net.UnknownHostException;
+
+class SmbTree {
+
+       int tid;
+       String path;
+       String service = jcifs.Config.getProperty( "jcifs.smb.client.serviceType", "?????" );
+       SmbSession session;
+       boolean treeConnected = false;
+
+       SmbTree( SmbSession session, String path, String service ) {
+               this.session = session;
+               this.path = path;
+               if( service != null && service.startsWith( "??" ) == false ) {
+                       this.service = service;
+               }
+       }
+
+       boolean matches( String path, String service ) {
+               return this.path.equals( path ) &&
+                               ( service == null || service.startsWith( "??" ) ||
+                               this.service.equals( service ));
+       }
+       void sendTransaction( SmbComTransaction request,
+                                                               SmbComTransactionResponse response ) throws IOException {
+               // transactions are not batchable
+               treeConnect( null, null );
+               request.tid = tid;
+               session.sendTransaction( request, response );
+       }
+       void send( ServerMessageBlock request,
+                                                               ServerMessageBlock response ) throws IOException {
+               if( response != null ) {
+                       response.received = false;
+               }
+               treeConnect( request, response );
+               if( response != null && response.received ) {
+                       return;
+               }
+               request.tid = tid;
+               session.send( request, response );
+       }
+       synchronized void treeConnect( ServerMessageBlock andx, ServerMessageBlock andxResponse )
+                                                               throws IOException {
+
+               if( treeConnected ) {
+                       return;
+               }
+
+               Log.println( Log.WARNINGS, "smb tree connect warning",
+                               " requesting tree connect with path=" + path +
+                               ",service=" + service );
+
+               /*
+                * Tree Connect And X Request / Response
+                */
+
+               SmbComTreeConnectAndXResponse response =
+                                                                       new SmbComTreeConnectAndXResponse( andxResponse );
+               SmbComTreeConnectAndX request =
+                                                                       new SmbComTreeConnectAndX( session, path, service, andx );
+               session.send( request, response );
+
+               tid = response.tid;
+               service = response.service;
+               treeConnected = true;
+       }
+       synchronized void treeDisconnect() {
+               if( treeConnected == false ) {
+                       return;
+               }
+               try {
+                       send( new SmbComTreeDisconnect(), null );
+               } catch( IOException ioe ) {
+                       Log.printStackTrace( "smb tree disconnect exception", ioe );
+               } finally {
+                       treeConnected = false;
+               }
+       }
+
+//
+// Not used at the moment.
+//
+//     boolean checkDirectory( String path ) throws IOException {
+//
+//             Log.println( Log.WARNINGS, "smb check directory warning",
+//                             " checking directory with path=" + path );
+//
+//             /*
+//              * Check Directory Request / Response
+//              */
+//
+//             try {
+//                     send( new SmbComCheckDirectory( path ), new SmbComBlankResponse() );
+//             } catch( SmbException se ) {
+//                     if( se.errorClass == SmbException.ERRDOS &&
+//                                                                     se.errorCode == SmbException.ERRbadpath ) {
+//                             return false;
+//                     } else {
+//                             throw se;
+//                     }
+//             }
+//             return true;
+//     }
+
+       Info queryPath( String path, int infoLevel ) throws IOException {
+
+               Log.println( Log.WARNINGS, "smb query path warning",
+                               " querying path=" + path );
+
+               /* To query server capabilities we must ensure the negotiation has talken place
+                */
+
+               synchronized( this ) {
+                       session.transport.negotiate();
+               }
+
+               /* normally we'd check the negotiatedCapabilities for CAP_NT_SMBS
+                * however I can't seem to get a good last modified time from
+                * SMB_COM_QUERY_INFORMATION so if NT_SMBs are requested
+                * by the server than in this case that's what it will get
+                * regardless of what jcifs.smb.client.useNTSmbs is set
+                * to(overrides negotiatedCapabilities).
+                */
+
+               Info result = null;
+               if(( session.transport.server.capabilities &
+                                                                       ServerMessageBlock.CAP_NT_SMBS ) ==
+                                                                       ServerMessageBlock.CAP_NT_SMBS ) {
+                       /*
+                        * Trans2 Query Path Information Request / Response
+                        */
+
+                       Trans2QueryPathInformationResponse response =
+                                                                       new Trans2QueryPathInformationResponse( infoLevel );
+                       try {
+                               sendTransaction( new Trans2QueryPathInformation( path, infoLevel ), response );
+                       } catch( SmbException se ) {
+                               if( se.errorClass == SmbException.ERRDOS &&
+                                                                               se.errorCode == SmbException.ERRbadfile ) {
+                                       return null;
+                               } else {
+                                       throw se;
+                               }
+                       }
+                       result = response.info;
+               } else {
+
+                       /*
+                        * Query Information Request / Response
+                        */
+
+                       SmbComQueryInformationResponse response =
+                                               new SmbComQueryInformationResponse(
+                                               session.transport.server.serverTimeZone * 1000 * 60L );
+                       try {
+                               send( new SmbComQueryInformation( path ), response );
+                       } catch( SmbException se ) {
+                               if( se.errorClass == SmbException.ERRDOS &&
+                                                                               se.errorCode == SmbException.ERRbadfile ) {
+                                       return null;
+                               } else {
+                                       throw se;
+                               }
+                       }
+                       result = response;
+               }
+               return result;
+       }
+       String[] find( String path ) throws IOException {
+               int sid, count, i, j;
+               String[] results;
+               String filename;
+
+               synchronized( this ) {
+                       // Must ensure treeConnect has been issued to query the service type
+                       treeConnect( null, null );
+               }
+
+               if( service.equals( "A:" ) == false ) {
+                       // Cannot issue find on anything but a Disk Share
+                       return new String[0];
+               }
+
+               if( path.equals( "\\" )) {
+                       path = "\\*";
+               } else {
+                       path += "\\*";
+               }
+
+               Log.println( Log.WARNINGS, "smb find warning",
+                               " find with path=" + path );
+
+               Trans2FindFirst2Response response = new Trans2FindFirst2Response();
+               sendTransaction( new Trans2FindFirst2( path ), response );
+
+               sid = response.sid;
+               count = response.searchCount;
+               j = 0;
+
+               results = new String[Math.max( 10, count )];
+               /*
+                * using hashCode is much more efficient than
+                * filename.equals( "." ) || filename.equals( ".." )
+                */
+               int h1 = new String( "." ).hashCode();
+               int h2 = new String( ".." ).hashCode();
+               i = 0;
+               while( j < count ) {
+                       filename = response.results[i++].filename;
+                       if( filename.length() < 3 ) {
+                               int h = filename.hashCode();
+                               if( h == h1 || h == h2 ) {
+                                       count--;
+                                       continue;
+                               }
+                       }
+                       results[j++] = filename;
+               }
+
+               // only difference between first2 and next2 responses is subCommand so let's recycle
+               response.subCommand = SmbComTransaction.TRANS2_FIND_NEXT2;
+
+               while( response.isEndOfSearch == false && response.searchCount > 0 ) {
+                       sendTransaction( new Trans2FindNext2( sid, response.resumeKey,
+                                                                                                       response.lastName ), response );
+                       count += response.searchCount;
+
+                       if( count > results.length ) {
+                               String[] tmp = results;
+                               results = new String[Math.max( results.length * 2, count )];
+                               System.arraycopy( tmp, 0, results, 0, j );
+                       }
+                       i = 0;
+                       while( j < count ) {
+                               filename = response.results[i++].filename;
+                               if( filename.length() < 3 ) {
+                                       int h = filename.hashCode();
+                                       if( h == h1 || h == h2 ) {
+                                               count--;
+                                               continue;
+                                       }
+                               }
+                               results[j++] = filename;
+                       }
+               }
+
+               try {
+                       send( new SmbComFindClose2( sid ), new SmbComBlankResponse() );
+               } catch( SmbException se ) {
+                       Log.printStackTrace( "smb find close response exception", se );
+               }
+
+               if( results.length != count ) {
+                       String[] tmp = results;
+                       results = new String[count];
+                       System.arraycopy( tmp, 0, results, 0, count );
+               }
+
+               return results;
+       }
+       String[] netShareEnum() throws IOException {
+               String ipcPath = path.substring( 0, path.lastIndexOf( '\\' ) + 1 ) + "IPC$";
+               SmbTree t = session.getSmbTree( ipcPath, null );
+
+               NetShareEnumResponse response = new NetShareEnumResponse();
+               t.sendTransaction( new NetShareEnum(), response );
+
+               if( response.status != 0 &&
+                                                       response.status != NetShareEnumResponse.ERROR_MORE_DATA ) {
+                       throw new IOException( response.toString() );
+               }
+
+               String[] ret = new String[response.entriesReturned];
+               for( int i = 0; i < response.entriesReturned; i++ ) {
+                       ret[i] = response.results[i].netName;
+               }
+
+               return ret;
+       }
+       static void setLmbTree( SmbFile file ) throws IOException {
+               NbtAddress lmb = NbtAddress.getByName( NbtAddress.MASTER_BROWSER_NAME, 0x01, null );
+               lmb = NbtAddress.getByName( lmb.getHostAddress() );
+               file.address = NbtAddress.getByName( lmb.getHostAddress(), 0x20, null );
+               SmbTransport trans = SmbTransport.getSmbTransport( file.address, 0 );
+               SmbSession ssn = trans.getSmbSession( "", "", "" );
+               String unc = new String( "\\\\" + file.address.getHostName() +
+                                                                                                                       "\\IPC$" ).toUpperCase();
+               file.tree = ssn.getSmbTree( unc, null );
+       }
+       String[] domainEnum() throws IOException {
+               String ipcPath = path.substring( 0, path.lastIndexOf( '\\' ) + 1 ) + "IPC$";
+               SmbTree t = session.getSmbTree( ipcPath, null );
+
+               synchronized( this ) {
+                       // to query oemDomainName megotiation must have occurred
+                       t.session.transport.negotiate();
+               }
+
+               NetServerEnum2Response response = new NetServerEnum2Response();
+               t.sendTransaction( new NetServerEnum2( t.session.transport.server.oemDomainName,
+                                                                       NetServerEnum2.SV_TYPE_DOMAIN_ENUM ), response );
+
+               if( response.status != NetServerEnum2Response.NERR_Success &&
+                               response.status != NetServerEnum2Response.ERROR_MORE_DATA ) {
+                       throw new IOException( response.toString() );
+               }
+
+               String[] ret = new String[response.entriesReturned];
+               for( int i = 0; i < response.entriesReturned; i++ ) {
+                       ret[i] = response.results[i].name;
+               }
+               return ret;
+       }
+       String[] netServerEnum2( String domain ) throws IOException {
+               NetServerEnum2Response response = new NetServerEnum2Response();
+               sendTransaction( new NetServerEnum2( domain, NetServerEnum2.SV_TYPE_ALL ), response );
+
+               if( response.status != NetServerEnum2Response.NERR_Success &&
+                               response.status != NetServerEnum2Response.ERROR_MORE_DATA ) {
+                       throw new IOException( response.toString() );
+               }
+
+               String[] ret = new String[response.entriesReturned];
+               for( int i = 0; i < response.entriesReturned; i++ ) {
+                       ret[i] = response.results[i].name;
+               }
+               return ret;
+       }
+       boolean rename( String oldFileName, String newFileName ) throws IOException {
+
+               Log.println( Log.WARNINGS, "smb rename warning",
+                               " oldFileName=" + oldFileName +
+                               ",newFileName=" + newFileName );
+
+               /*
+                * Rename Request / Response
+                */
+
+               SmbComBlankResponse response = new SmbComBlankResponse();
+               try {
+                       send( new SmbComRename( oldFileName, newFileName ), response );
+               } catch( SmbException se ) {
+                       if( se.errorClass == SmbException.ERRDOS &&
+                                                                       ( se.errorCode == SmbException.ERRbadpath ||
+                                                                       se.errorCode == SmbException.ERRbadfile )) {
+                               return false;
+                       } else {
+                               throw se;
+                       }
+               }
+               return true;
+       }
+
+//
+// Not used at the moment.
+//
+//     boolean copy( String sourceFileName, String targetFileName, int tid2 )
+//                                                                                                     throws IOException {
+//
+//             Log.println( Log.WARNINGS, "smb copy warning",
+//                             " sourceFileName=" + sourceFileName +
+//                             ",targetFileName=" + targetFileName );
+//
+//             /*
+//              * Copy Request / Response
+//              */
+//
+//             SmbComCopyResponse response = new SmbComCopyResponse();
+//             try {
+//                     send( new SmbComCopy( sourceFileName, targetFileName, tid2 ), response );
+//             } catch( SmbException se ) {
+//                     if( se.errorClass == SmbException.ERRDOS &&
+//                                                                     ( se.errorCode == SmbException.ERRbadpath ||
+//                                                                     se.errorCode == SmbException.ERRbadfile )) {
+//                             return false;
+//                     } else {
+//                             throw se;
+//                     }
+//             }
+//             return true;
+//     }
+
+       boolean delete( String fileName, boolean isDirectory ) throws IOException {
+
+               Log.println( Log.WARNINGS, "smb delete warning",
+                               " fileName=" + fileName );
+
+               /*
+                * Delete or Delete Directory Request / Response
+                */
+
+               ServerMessageBlock request;
+               if( isDirectory ) {
+
+                       /* Recursively delete directory contents using post order DFS
+                        */
+
+                       String[] list = find( fileName );
+                       for( int i = 0; i < list.length; i++ ) {
+                               String p = fileName + "\\" + list[i];
+                               int infoLevel = Trans2QueryPathInformationResponse.SMB_QUERY_FILE_BASIC_INFO;
+                               Info info = queryPath( p, infoLevel );
+                               boolean dir = ( info.getAttributes() & SmbFile.ATTR_DIRECTORY ) ==
+                                                                                                               SmbFile.ATTR_DIRECTORY;
+                               delete( p, dir );
+                       }
+
+                       request = new SmbComDeleteDirectory( fileName );
+               } else {
+                       request = new SmbComDelete( fileName );
+               }
+
+               try {
+                       send( request, new SmbComBlankResponse() );
+               } catch( SmbException se ) {
+                       if( se.errorClass == SmbException.ERRDOS &&
+                                                                       ( se.errorCode == SmbException.ERRbadpath ||
+                                                                       se.errorCode == SmbException.ERRbadfile )) {
+                               return false;
+                       } else {
+                               throw se;
+                       }
+               }
+               return true;
+       }
+       int open( String name, int flags ) throws IOException {
+
+               Log.println( Log.WARNINGS, "smb open warning", " name=" + name );
+
+               /*
+                * Open AndX Request / Response
+                */
+
+               /* To query server capabilities we must ensure the negotiation has talken place
+                */
+
+               synchronized( this ) {
+                       session.transport.negotiate();
+               }
+
+               if(( session.transport.negotiatedCapabilities &
+                                                                       ServerMessageBlock.CAP_NT_SMBS ) ==
+                                                                       ServerMessageBlock.CAP_NT_SMBS ) {
+                       SmbComNTCreateAndXResponse response = new SmbComNTCreateAndXResponse();
+                       send( new SmbComNTCreateAndX( name, flags, null ), response );
+                       return response.fid;
+               } else {
+                       SmbComOpenAndXResponse response = new SmbComOpenAndXResponse();
+                       send( new SmbComOpenAndX( name, flags, null ), response );
+                       return response.fid;
+               }
+       }
+       boolean createDirectory( String directoryName ) throws IOException {
+
+               Log.println( Log.WARNINGS, "smb create directory warning",
+                               " directoryName=" + directoryName );
+
+               /*
+                * Create Directory Request / Response
+                */
+
+               try {
+                       send( new SmbComCreateDirectory( directoryName ), new SmbComBlankResponse() );
+               } catch( SmbException se ) {
+                       if( se.errorClass == SmbException.ERRDOS &&
+                                                                       se.errorCode == SmbException.ERRnoaccess ) {
+                               return false;
+                       } else {
+                               throw se;
+                       }
+               }
+               return true;
+       }
+       public String toString() {
+               return "SmbTree[path=" + path +
+                       ",service=" + service +
+                       ",tid=" + tid + "]";
+       }
+}
diff --git a/src/jcifs/smb/SmbURL.java b/src/jcifs/smb/SmbURL.java
new file mode 100644 (file)
index 0000000..647f4e1
--- /dev/null
@@ -0,0 +1,346 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.netbios.NbtAddress;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.util.Vector;
+import java.util.Enumeration;
+
+final class SmbURL {
+       String url;
+       String domain;
+       String username;
+       String password;
+       String server;
+       int port;
+       String share;
+       String canonicalPath;
+       String path;
+       String file;
+       boolean isWorkgroup;
+
+       static class QueryThread extends Thread {
+
+               Object lock;
+               String host, scope;
+               int type;
+               NbtAddress ans = null;
+               UnknownHostException uhe;
+
+               QueryThread( Object lock, String host, int type, String scope ) {
+                       this.lock = lock;
+                       this.host = host;
+                       this.type = type;
+                       this.scope = scope;
+               }
+               public void run() {
+                       try {
+                               ans = NbtAddress.getByName( host, type, scope );
+                       } catch( UnknownHostException uhe ) {
+                               this.uhe = uhe;
+                       }
+                       synchronized( lock ) {
+                               lock.notify();
+                       }
+               }
+       }
+       static NbtAddress lookupServerOrWorkgroup( String name ) throws UnknownHostException {
+               Object lock = new Object();
+               QueryThread q1d = new QueryThread( lock, name, 0x1d, null );
+               QueryThread q20 = new QueryThread( lock, name, 0x20, null );
+               q1d.setDaemon( true );
+               q20.setDaemon( true );
+               try {
+                       synchronized( lock ) {
+                               q1d.start();
+                               q20.start();
+
+                               int i = 2;
+                               while( i-- > 0 && q1d.ans == null && q20.ans == null ) {
+                                       lock.wait();
+                               }
+                       }
+               } catch( InterruptedException ie ) {
+                       throw new UnknownHostException( name );
+               }
+               if( q1d.ans != null ) {
+                       return NbtAddress.getByName( q1d.ans.getHostAddress(), 0x1d, null );
+               } else if( q20.ans != null ) {
+                       return q20.ans;
+               } else {
+                       throw q1d.uhe;
+               }
+       }
+
+       /*
+        * smb://[[[ntdomain;]user[:password]@]server[:port][/share[/path]]]
+        *
+        * smb://hendrix/download/
+        * smb://nycdom;mike@angus/tmp/classes/Main.class
+        * smb://mike:sw@#ii@angus/tmp/classes
+        * smb://nycdom;mike:sw@#ii@hendrix/download/docs/index.html
+        */
+
+       SmbURL( String url ) throws MalformedURLException, UnknownHostException {
+               this( url, null, 4, url.length() );
+       }
+       SmbURL( String url, String name ) throws MalformedURLException, UnknownHostException {
+               this( url, name, 4, url.length() );
+       }
+       SmbURL( String url, String name, int start, int limit )
+                                                                               throws MalformedURLException, UnknownHostException {
+               int beg, end, c, at, srv, pat;
+
+               this.url = url;
+
+               try {
+                       if( name != null ) {
+                               if( name.regionMatches( true, 0, "smb://", 0, 6 )) {
+
+                                       /* If the secondard argument begins with
+                                        * 'smb://' then we simply replace the
+                                        * primary url argument with it and proceed
+                                        * as usuall.
+                                        */
+
+                                       url = name;
+                                       name = null;
+                                       start = 4;
+                                       limit = url.length();
+                               } else if( url.equalsIgnoreCase( "smb://" )) {
+                                       url = "smb://" + name;
+                                       name = null;
+                                       start = 4;
+                                       limit = url.length();
+                               }
+                       }
+
+                       beg = start + 2;
+                       end = limit;
+                       if( end > beg ) {
+                               while( end > beg && url.charAt( end - 1 ) == '/' ) {
+                                       end--; // trim trailing slashes
+                               }
+                               while( beg < end && url.charAt( beg ) != '/' && url.charAt( beg ) != '@' ) {
+                                       beg++;
+                               }
+                               if( beg == end && Character.isDigit( url.charAt( start + 2 )) == false ) {
+                                       // Could be a workgroup. Need to query the network to find out.
+                                       NbtAddress ans = lookupServerOrWorkgroup( url.substring( 6, end ));
+                                       if( ans.getNameType() == 0x1d ) {
+                                               if( name != null ) {
+                                                       url = "smb://" + name;
+                                                       name = null;
+                                                       start = 4;
+                                                       limit = url.length();
+                                               } else {
+                                                       isWorkgroup = true;
+                                               }
+                                       }
+                               }
+                       }
+
+                       if( url.startsWith( "smb://" ) == false ) {
+                               throw new MalformedURLException();
+                       }
+
+                       /* The java.net.URL parsing model always provides
+                        * a start point of right after the ':'. So in the
+                        * case of 'smb://' this would always be position
+                        * 4. Because smb:// URLs always have 2 following
+                        * slashes we can just bump-up start by 2 here
+                        */
+
+                       start += 2;
+                       srv = start;
+
+                       at = url.lastIndexOf( '@' );
+                       if( at != -1 ) {
+                               // server right after '@'
+                               srv = at + 1;
+
+                               // parse authentication info
+                               int u = start;
+                               int i = start;
+                               for( i = start; i < at; i++ ) {
+                                       c = url.charAt( i );
+                                       if( c == ';' ) {
+                                               domain = url.substring( start, i );
+                                               u = i + 1;
+                                       } else if( c == ':' ) {
+                                               password = url.substring( i + 1, at );
+                                               break;
+                                       }
+                               }
+                               username = url.substring( u, i );
+                       }
+
+                       server = url.substring( srv );
+
+                       /* For the moment the server variable will
+                        * contain everything that follows as well for
+                        * feeding to the canonicalization via make-shift
+                        * stack routine below. After that, the server,
+                        * share, path, etc will be isolated.
+                        */
+
+                       if( name != null && name.length() != 0 ) {
+
+                               /* A secondary argument was provided. If
+                                * it begins with '/' then we replace
+                                * everything after the server with
+                                * name. Otherwise we simply concatonate
+                                * it onto the current path.
+                                */
+
+                               if( name.charAt( 0 ) == '/' ) {
+                                       int sha = url.indexOf( '/', srv );
+                                       if( sha < srv ) {
+                                               sha = limit;
+                                       }
+                                       server = url.substring( srv, sha ) + name;
+                               } else {
+                                       if( server.length() == 0 || server.endsWith( "/" )) {
+                                               server += name;
+                                       } else {
+                                               server = server + '/' + name;
+                                       }
+                               }
+                       }
+                       limit = server.length();
+
+                       /* The path must preserve all that was provided in
+                        * the primary url argument and possibly secondary
+                        * argument such that it could be fed back into the
+                        * constructor of an SmbURL and the results would
+                        * be equal.
+                        */
+
+                       path = server;
+
+                       Vector stk = new Vector();
+                       String str;
+                       for( int i = 0, s = 0; i <= limit; i++ ) {
+                               if( i == limit || server.charAt( i ) == '/' ) {
+                                       if( i > s ) {
+                                               str = server.substring( s, i );
+                                               if( str.equals( ".." )) {
+                                                       if( stk.isEmpty() == false ) {
+                                                               stk.removeElementAt( stk.size() - 1 );
+                                                       }
+                                               } else if( str.equals( "." )) {
+                                               } else {
+                                                       stk.addElement( str );
+                                               }
+                                       }
+                                       s = i + 1;
+                               }
+                       }
+
+                       server = null;
+                       if( stk.isEmpty() == false ) {
+                               Enumeration e = stk.elements();
+                               server = (String)e.nextElement();
+
+                               int p = server.indexOf( ':' );
+                               if( p > 0 ) {
+                                       port = Integer.parseInt( server.substring( p + 1 ));
+                                       server = server.substring( 0, p );
+                               }
+
+                               file = server;
+                               if( e.hasMoreElements() ) {
+                                       StringBuffer sb = new StringBuffer();
+
+                                       share = (String)e.nextElement();
+                                       file = share;
+
+                                       while( e.hasMoreElements() ) {
+                                               file = (String)e.nextElement();
+                                               sb.append( '/' ).append( file );
+                                       }
+
+                                       if( sb.length() > 0 ) {
+                                               canonicalPath = sb.toString();
+                                       }
+                               }
+                       }
+               } catch( UnknownHostException uhe ) {
+                       throw uhe;
+               } catch( Exception e ) {
+                       throw new MalformedURLException( url + ", " + name );
+               }
+       }
+
+       public boolean equals( Object obj ) {
+               return obj instanceof SmbURL && obj.hashCode() == hashCode();
+       }
+       public int hashCode() {
+               return toString().hashCode();
+       }
+       String getCanonicalPath() {
+               StringBuffer sb = new StringBuffer( "smb://" );
+               if( server == null ) {
+                       return "smb://";
+               } else if( username != null ) {
+                       if( domain != null ) {
+                               sb.append( domain ).append( ';' );
+                       }
+                       sb.append( username );
+                       if( password != null ) {
+                               sb.append( ':' ).append( password );
+                       }
+                       sb.append( '@' );
+               }
+               sb.append( server );
+               // should probably not put the netbios session service
+               // port in here like this :~(
+               if( port != 0 && port != 139 ) {
+                       sb.append( ":" ).append( port );
+               }
+               if( share != null ) {
+                       sb.append( '/' ).append( share );
+                       if( canonicalPath != null ) {
+                               sb.append( canonicalPath );
+                       }
+               }
+               return sb.toString();
+       }
+       public String toString() {
+               StringBuffer sb = new StringBuffer( "smb://" );
+               if( username != null ) {
+                       if( domain != null ) {
+                               sb.append( domain ).append( ';' );
+                       }
+                       sb.append( username );
+                       if( password != null ) {
+                               sb.append( ':' ).append( password );
+                       }
+                       sb.append( '@' );
+               }
+               if( server != null ) {
+                       sb.append( path );
+               }
+               return sb.toString();
+       }
+}
+
diff --git a/src/jcifs/smb/SmbURLConnection.java b/src/jcifs/smb/SmbURLConnection.java
new file mode 100644 (file)
index 0000000..6a257db
--- /dev/null
@@ -0,0 +1,132 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.net.URLConnection;
+import java.net.URL;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/** 
+ * This class represents a communications link between an application and
+ * an SMB resource represented by a {@link java.net.URL}. An object of this type will be
+ * returned by the <code>java.net.URL openConnection</code> method when an SMB URL is
+ * used. See the {@link jcifs.smb.SmbFile} class for a detailed decription of
+ * the smb URL syntax with examples.
+ *
+ * Before referencing a <code>java.net.URL</code> or code that uses one
+ * with SMB URLs, the <code>jcifs.Config</code> class must be loaded. It
+ * contains a static initializer that installs the SMB specific protocol
+ * handler. If this protocol handler is not loaded the following Exception
+ * will occur:
+ * 
+ * <blockquote><pre>
+ * java.net.MalformedURLException: unknown protocol: smb
+ * </pre></blockquote>
+ * 
+ * It may be loaded by simply using the <code>jcifs.Config</code> class
+ * or if for no other reason the following code will do:
+ * 
+ * <blockquote><pre>
+ * Class.forName( "jcifs.Config" );
+ * </pre></blockquote>
+ *
+ * In general this class is deficient; it only supports downloading
+ * via an <code>InputStream</code>. Adding more functionality is strait
+ * forward. If you require more functionality please express your intrest
+ * to the jcifs@samba.org mailing list.
+ */ 
+
+public class SmbURLConnection extends URLConnection {
+
+       SmbURL url;
+       SmbFile file;
+
+       SmbURLConnection( URL u, SmbURL url ) {
+               super( u );
+               this.url = url;
+       }
+
+/** 
+ * Issue the actual socket IO necesary to open a connection with the server
+ * hosting the target resource.
+ */ 
+
+       public void connect() throws IOException {
+               if( connected ) {
+                       return;
+               }
+               file = new SmbFile( url.getCanonicalPath() );
+       }
+
+/**
+ * Return the length in bytes of the resource specified by the URL.
+ */
+
+       public int getContentLength() {
+               try {
+                       connect();
+                       return (int)file.length();
+               } catch( IOException ioe ) {
+               }
+               return 0;
+       }
+
+/**
+ * Retrieves the last modified time of the file or directory specified by
+ * the URL for this connection.
+ */
+
+       public long getDate() {
+               return getLastModified();
+       }
+
+/**
+ * Retrieves the last modified time of the file or directory specified by
+ * the URL for this connection.
+ */
+
+       public long getLastModified() {
+               try {
+                       connect();
+                       return file.lastModified();
+               } catch( IOException ioe ) {
+               }
+               return 0L;
+       }
+
+/**
+ * Create an <code>InputStream</code> from which bytes may be read from
+ * the taget specified by the URL of this connection.
+ */
+
+       public InputStream getInputStream() throws IOException {
+               connect();
+               return new SmbFileInputStream( file );
+       }
+
+/**
+ * Return a String representing this object.
+ */
+
+       public String toString() {
+               return new String( "SmbURLConnection[url=" + url.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/Trans2FindFirst2.java b/src/jcifs/smb/Trans2FindFirst2.java
new file mode 100644 (file)
index 0000000..6422401
--- /dev/null
@@ -0,0 +1,114 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.Config;
+
+class Trans2FindFirst2 extends SmbComTransaction {
+
+
+       // information levels
+
+       static final int SMB_INFO_STANDARD                 = 1;
+       static final int SMB_INFO_QUERY_EA_SIZE            = 2;
+       static final int SMB_INFO_QUERY_EAS_FROM_LIST      = 3;
+       static final int SMB_FIND_FILE_DIRECTORY_INFO      = 0x101;
+       static final int SMB_FIND_FILE_FULL_DIRECTORY_INFO = 0x102;
+       static final int SMB_FILE_NAMES_INFO               = 0x103;
+       static final int SMB_FILE_BOTH_DIRECTORY_INFO      = 0x104;
+
+       // flags
+
+       static final int FLAGS_CLOSE_AFTER_THIS_REQUEST = 0x01;
+       static final int FLAGS_CLOSE_IF_END_REACHED     = 0x02;
+       static final int FLAGS_RETURN_RESUME_KEYS       = 0x04;
+       static final int FLAGS_RESUME_FROM_PREVIOUS_END = 0x08;
+       static final int FLAGS_FIND_WITH_BACKUP_INTENT  = 0x10;
+
+       
+       static final int DEFAULT_MAX_DATA_COUNT = 1200;
+       static final int DEFAULT_SEARCH_COUNT = 15;
+
+       int searchAttributes;
+       int searchCount;
+       int flags;
+       int informationLevel;
+       int searchStorageType = 0;
+       String filename;
+
+       Trans2FindFirst2( String filename ) {
+               this.filename = filename;
+               command = SMB_COM_TRANSACTION2;
+               subCommand = TRANS2_FIND_FIRST2;
+
+               searchAttributes = ATTR_DIRECTORY | ATTR_HIDDEN | ATTR_SYSTEM;
+               searchCount = Config.getInt( "jcifs.smb.client.listCount", DEFAULT_SEARCH_COUNT );
+               flags = 0x00;
+               informationLevel = SMB_FILE_BOTH_DIRECTORY_INFO;
+
+               totalDataCount = 0;
+               maxParameterCount = 10;
+               maxDataCount = Config.getInt( "jcifs.smb.client.listSize", DEFAULT_MAX_DATA_COUNT );
+               maxSetupCount = 0;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = subCommand;
+               dst[dstIndex++] = (byte)0x00;
+               return 2;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               writeInt2( searchAttributes, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( searchCount, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( flags, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( informationLevel, dst, dstIndex );
+               dstIndex += 2;
+               writeInt4( searchStorageType, dst, dstIndex );
+               dstIndex += 4;
+               dstIndex += writeString( filename, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "Trans2FindFirst2[" + super.toString() +
+                       ",searchAttributes=0x" + Log.getHexString( searchAttributes, 2 ) +
+                       ",searchCount=" + searchCount +
+                       ",flags=0x" + Log.getHexString( flags, 2 ) +
+                       ",informationLevel=0x" + Log.getHexString( informationLevel, 3 ) +
+                       ",searchStorageType=" + searchStorageType +
+                       ",filename=" + filename + "]" );
+       }
+}
diff --git a/src/jcifs/smb/Trans2FindFirst2Response.java b/src/jcifs/smb/Trans2FindFirst2Response.java
new file mode 100644 (file)
index 0000000..8aa860c
--- /dev/null
@@ -0,0 +1,228 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+
+class Trans2FindFirst2Response extends SmbComTransactionResponse {
+
+       // information levels
+
+       static final int SMB_INFO_STANDARD                 = 1;
+       static final int SMB_INFO_QUERY_EA_SIZE            = 2;
+       static final int SMB_INFO_QUERY_EAS_FROM_LIST      = 3;
+       static final int SMB_FIND_FILE_DIRECTORY_INFO      = 0x101;
+       static final int SMB_FIND_FILE_FULL_DIRECTORY_INFO = 0x102;
+       static final int SMB_FILE_NAMES_INFO               = 0x103;
+       static final int SMB_FILE_BOTH_DIRECTORY_INFO      = 0x104;
+
+       class SmbFindFileBothDirectoryInfo {
+               int nextEntryOffset;
+               int fileIndex;
+               long creationTime;
+               long lastAccessTime;
+               long lastWriteTime;
+               long changeTime;
+               long endOfFile;
+               long allocationSize;
+               int extFileAttributes;
+               int fileNameLength;
+               int eaSize;
+               int shortNameLength;
+               String shortName;
+               String filename;
+
+               public String toString() {
+                       return new String( "SmbFindFileBothDirectoryInfo[" +
+                               "nextEntryOffset=" + nextEntryOffset +
+                               ",fileIndex=" + fileIndex +
+                               ",creationTime=" + new Date( creationTime ) +
+                               ",lastAccessTime=" + new Date( lastAccessTime ) +
+                               ",lastWriteTime=" + new Date( lastWriteTime ) +
+                               ",changeTime=" + new Date( changeTime ) +
+                               ",endOfFile=" + endOfFile +
+                               ",allocationSize=" + allocationSize +
+                               ",extFileAttributes=" + extFileAttributes +
+                               ",fileNameLength=" + fileNameLength +
+                               ",eaSize=" + eaSize +
+                               ",shortNameLength=" + shortNameLength +
+                               ",shortName=" + shortName +
+                               ",filename=" + filename + "]" );
+               }
+       }
+
+       int sid;
+       int searchCount;
+       boolean isEndOfSearch;
+       int eaErrorOffset;
+       int lastNameOffset, lastNameBufferIndex;
+       String lastName;
+       int resumeKey;
+
+       SmbFindFileBothDirectoryInfo[] results;
+
+       Trans2FindFirst2Response() {
+               command = SMB_COM_TRANSACTION2;
+               subCommand = SmbComTransaction.TRANS2_FIND_FIRST2;
+       }
+
+       String readString( byte[] src, int srcIndex, int len ) {
+               String str = null;
+               if( useUnicode ) {
+                       // should Unicode alignment be corrected for here?
+                       try {
+                               str = new String( src, srcIndex, len, "UnicodeLittle" );
+                       } catch( UnsupportedEncodingException uee ) {
+                               Log.printStackTrace( "smb exception", uee );
+                       }
+               } else {
+
+                       /* On NT without Unicode the fileNameLength
+                        * includes the '\0' whereas on win98 it doesn't. I
+                        * guess most clients only support non-unicode so
+                        * they don't run into this.
+                        */
+
+/* UPDATE: Maybe not! Could this be a Unicode alignment issue. I hope
+ * so. We cannot just comment out this method and use readString of
+ * ServerMessageBlock.java because the arguments are different, however
+ * one might be able to reduce this.
+ */
+
+                       if( len > 0 && src[srcIndex + len - 1] == '\0' ) {
+                               len--;
+                       }
+                       str = new String( src, srcIndex, len );
+               }
+               return str;
+       }
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               int start = bufferIndex;
+
+               if( subCommand == SmbComTransaction.TRANS2_FIND_FIRST2 ) {
+                       sid = readInt2( buffer, bufferIndex );
+                       bufferIndex += 2;
+               }
+               searchCount = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               isEndOfSearch = ( buffer[bufferIndex] & 0x01 ) == 0x01 ? true : false;
+               bufferIndex += 2;
+               eaErrorOffset = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               lastNameOffset = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+
+               return bufferIndex - start;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               int start = bufferIndex;
+
+               lastNameBufferIndex = bufferIndex + lastNameOffset;
+
+               results = new SmbFindFileBothDirectoryInfo[searchCount];
+
+               for( int i = 0; i < searchCount; i++ ) {
+                       results[i] = new SmbFindFileBothDirectoryInfo();
+
+                       results[i].nextEntryOffset = readInt4( buffer, bufferIndex );
+                       results[i].fileIndex = readInt4( buffer, bufferIndex + 4 );
+                       results[i].creationTime = readTime( buffer, bufferIndex + 8 );
+                       results[i].lastAccessTime = readTime( buffer, bufferIndex + 16 );
+                       results[i].lastWriteTime = readTime( buffer, bufferIndex + 24 );
+                       results[i].changeTime = readTime( buffer, bufferIndex + 32 );
+                       results[i].endOfFile = readLong( buffer, bufferIndex + 40 );
+                       results[i].allocationSize = readLong( buffer, bufferIndex + 48 );
+                       results[i].extFileAttributes = readInt4( buffer, bufferIndex + 56 );
+                       results[i].fileNameLength = readInt4( buffer, bufferIndex + 60 );
+                       results[i].eaSize = readInt4( buffer, bufferIndex + 64 );
+                       results[i].shortNameLength = buffer[bufferIndex + 68] & 0xFF;
+
+                       /* With NT, the shortName is in Unicode regardless of what is negotiated.
+                        */
+
+                       results[i].shortName = readString( buffer, bufferIndex + 70,
+                                                                                                               results[i].shortNameLength );
+                       results[i].filename = readString( buffer, bufferIndex + 94,
+                                                                                                               results[i].fileNameLength );
+
+//Log.println( Log.DEBUGGING, "Trans2FindFirst2/Next2Response debugging", "bufferIndex=" + bufferIndex + ",lastNameBufferIndex=" + lastNameBufferIndex + ",nextEntryOffet=" + ( bufferIndex + results[i].nextEntryOffset ));
+
+                       /* lastNameOffset ends up pointing to either to
+                        * the exact location of the filename(e.g. Win98)
+                        * or to the start of the entry containing the
+                        * filename(e.g. NT). Ahhrg! In either case the
+                        * lastNameOffset falls between the start of the
+                        * entry and the next entry.
+                        */
+
+                       if( lastNameBufferIndex >= bufferIndex &&
+                                               ( results[i].nextEntryOffset == 0 ||
+                                               lastNameBufferIndex < ( bufferIndex + results[i].nextEntryOffset ))) {
+                               lastName = results[i].filename;
+                               resumeKey = results[i].fileIndex;
+                       }
+
+//Log.println( Log.DEBUGGING, "info entry", results[i].toString() );
+
+                       bufferIndex += results[i].nextEntryOffset;
+               }
+
+
+               if( lastName == null ) {
+                       Log.println( Log.DEBUGGING, "Trans2FindFirst2/Next2Response debugging",
+                                                                                       "lastName was null!" );
+               }
+
+               /* last nextEntryOffset for NT 4(but not 98) is 0 so we must
+                * use dataCount or our accounting will report an error for NT :~(
+                */
+               
+               //return bufferIndex - start;
+
+               return dataCount;
+       }
+       public String toString() {
+               String c;
+               if( subCommand == SmbComTransaction.TRANS2_FIND_FIRST2 ) {
+                       c = "Trans2FindFirst2Response[";
+               } else {
+                       c = "Trans2FindNext2Response[";
+               }
+               return new String( c + super.toString() +
+                       ",sid=" + sid +
+                       ",searchCount=" + searchCount +
+                       ",isEndOfSearch=" + isEndOfSearch +
+                       ",eaErrorOffset=" + eaErrorOffset +
+                       ",lastNameOffset=" + lastNameOffset +
+                       ",lastName=" + lastName + "]" );
+       }
+}
diff --git a/src/jcifs/smb/Trans2FindNext2.java b/src/jcifs/smb/Trans2FindNext2.java
new file mode 100644 (file)
index 0000000..23902fd
--- /dev/null
@@ -0,0 +1,87 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import jcifs.Config;
+
+class Trans2FindNext2 extends SmbComTransaction {
+
+       int sid, searchCount, informationLevel, resumeKey, flags;
+       String filename;
+
+       Trans2FindNext2( int sid, int resumeKey, String filename ) {
+               this.sid = sid;
+               this.resumeKey = resumeKey;
+               this.filename = filename;
+               command = SMB_COM_TRANSACTION2;
+               subCommand = TRANS2_FIND_NEXT2;
+               searchCount = Config.getInt( "jcifs.smb.client.listCount",
+                                                                                               Trans2FindFirst2.DEFAULT_SEARCH_COUNT );
+               informationLevel = Trans2FindFirst2.SMB_FILE_BOTH_DIRECTORY_INFO;
+               flags = 0x00;
+               maxParameterCount = 8;
+               maxDataCount = Config.getInt( "jcifs.smb.client.listSize",
+                                                                                               Trans2FindFirst2.DEFAULT_MAX_DATA_COUNT );
+               maxSetupCount = 0;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = subCommand;
+               dst[dstIndex++] = (byte)0x00;
+               return 2;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               writeInt2( sid, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( searchCount, dst, dstIndex );
+               dstIndex += 2;
+               writeInt2( informationLevel, dst, dstIndex );
+               dstIndex += 2;
+               writeInt4( resumeKey, dst, dstIndex );
+               dstIndex += 4;
+               writeInt2( flags, dst, dstIndex );
+               dstIndex += 2;
+               dstIndex += writeString( filename, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "Trans2FindNext2[" + super.toString() +
+                       ",sid=" + sid +
+                       ",searchCount=" + searchCount +
+                       ",informationLevel=0x" + Log.getHexString( informationLevel, 3 ) +
+                       ",resumeKey=0x" + Log.getHexString( resumeKey, 4 ) +
+                       ",flags=0x" + Log.getHexString( flags, 2 ) +
+                       ",filename=" + filename + "]" );
+       }
+}
diff --git a/src/jcifs/smb/Trans2QueryFSInformation.jav b/src/jcifs/smb/Trans2QueryFSInformation.jav
new file mode 100644 (file)
index 0000000..f3c2db3
--- /dev/null
@@ -0,0 +1,72 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class Trans2QueryFSInformation extends SmbComTransaction {
+
+       int informationLevel;
+
+       Trans2QueryFSInformation() {
+               command = SMB_COM_TRANSACTION2;
+               subCommand = TRANS2_QUERY_FS_INFORMATION;
+               informationLevel = Trans2QueryFSInformationResponse.SMB_QUERY_FS_ATTRIBUTE_INFO;
+               totalParameterCount = 2;
+               totalDataCount = 0;
+               maxParameterCount = 0;
+               maxDataCount = 800;
+               maxSetupCount = 0;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = subCommand;
+               dst[dstIndex++] = (byte)0x00;
+               return 2;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               writeInt2( informationLevel, dst, dstIndex );
+               dstIndex += 2;
+
+               /* windows98 has what appears to be another 4 0's followed by the share
+                * name as a zero terminated ascii string "\TMP" + '\0'
+                *
+                * As is this works, but it deviates from the spec section 4.1.6.6 but
+                * maybe I should put it in. Wonder what NT does?
+                */
+
+               return dstIndex - start;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "Trans2QueryFSInformation[" + super.toString() +
+                       ",informationLevel=0x" + Log.getHexString( informationLevel, 3 ) + "]" );
+       }
+}
diff --git a/src/jcifs/smb/Trans2QueryFSInformationResponse.jav b/src/jcifs/smb/Trans2QueryFSInformationResponse.jav
new file mode 100644 (file)
index 0000000..db30391
--- /dev/null
@@ -0,0 +1,96 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.UnsupportedEncodingException;
+
+class Trans2QueryFSInformationResponse extends SmbComTransactionResponse {
+
+       // information levels
+       static final int SMB_QUERY_FS_ATTRIBUTE_INFO = 0x105;
+
+       class SmbQueryFSAttributeInfo implements Info {
+               int attributes;
+               int maxNameLength;
+               String name;
+
+               public int getAttributes() {
+                       return attributes;
+               }
+               public long getLastWriteTime() {
+                       return 0;
+               }
+               public long getSize() {
+                       return 0;
+               }
+               public String toString() {
+                       return new String( "SmbQueryFSAttributeInfo[" +
+                               "attributes=0x" + Log.getHexString( attributes, 4 ) +
+                               ",maxNameLength=" + maxNameLength +
+                               ",name=" + name + "]" );
+               }
+       }
+
+       Info info;
+
+       Trans2QueryFSInformationResponse() {
+               command = SMB_COM_TRANSACTION2;
+               subCommand = SmbComTransaction.TRANS2_QUERY_FS_INFORMATION;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               int start = bufferIndex;
+
+               SmbQueryFSAttributeInfo info = new SmbQueryFSAttributeInfo();
+               info.attributes = readInt4( buffer, bufferIndex );
+               bufferIndex += 4;
+               info.maxNameLength = readInt2( buffer, bufferIndex );
+               bufferIndex += 4;
+               int nameLength = readInt2( buffer, bufferIndex );
+               bufferIndex += 4;
+               try {
+                       info.name = new String( buffer, bufferIndex, nameLength, "UnicodeLittle" );
+               } catch( UnsupportedEncodingException uee ) {
+                       Log.printStackTrace( "", uee );
+               }
+               bufferIndex += nameLength;
+               this.info = info;
+
+               return bufferIndex - start;
+       }
+       public String toString() {
+               return new String( "Trans2QueryFSInformationResponse[" +
+                       super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/Trans2QueryPathInformation.java b/src/jcifs/smb/Trans2QueryPathInformation.java
new file mode 100644 (file)
index 0000000..a6739e2
--- /dev/null
@@ -0,0 +1,72 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class Trans2QueryPathInformation extends SmbComTransaction {
+
+       int informationLevel;
+       String filename;
+
+       Trans2QueryPathInformation( String filename, int informationLevel ) {
+               this.filename = filename;
+               this.informationLevel = informationLevel;
+               command = SMB_COM_TRANSACTION2;
+               subCommand = TRANS2_QUERY_PATH_INFORMATION;
+               totalDataCount = 0;
+               maxParameterCount = 2;
+               maxDataCount = 40;
+               maxSetupCount = (byte)0x00;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = subCommand;
+               dst[dstIndex++] = (byte)0x00;
+               return 2;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               int start = dstIndex;
+
+               writeInt2( informationLevel, dst, dstIndex );
+               dstIndex += 2;
+               dst[dstIndex++] = (byte)0x00;
+               dst[dstIndex++] = (byte)0x00;
+               dst[dstIndex++] = (byte)0x00;
+               dst[dstIndex++] = (byte)0x00;
+               dstIndex += writeString( filename, dst, dstIndex );
+
+               return dstIndex - start;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "Trans2QueryPathInformation[" + super.toString() +
+                       ",informationLevel=0x" + Log.getHexString( informationLevel, 3 ) +
+                       ",filename=" + filename + "]" );
+       }
+}
diff --git a/src/jcifs/smb/Trans2QueryPathInformationResponse.java b/src/jcifs/smb/Trans2QueryPathInformationResponse.java
new file mode 100644 (file)
index 0000000..be4b9a7
--- /dev/null
@@ -0,0 +1,152 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.util.Date;
+
+class Trans2QueryPathInformationResponse extends SmbComTransactionResponse {
+
+       // information levels
+       static final int SMB_QUERY_FILE_BASIC_INFO    = 0x101;
+       static final int SMB_QUERY_FILE_STANDARD_INFO = 0x102;
+
+       class SmbQueryFileBasicInfo implements Info {
+               long creationTime;
+               long lastAccessTime;
+               long lastWriteTime;
+               long changeTime;
+               int attributes;
+
+               public int getAttributes() {
+                       return attributes;
+               }
+               public long getLastWriteTime() {
+                       return lastWriteTime;
+               }
+               public long getSize() {
+                       return 0L;
+               }
+               public String toString() {
+                       return new String( "SmbQueryFileBasicInfo[" +
+                               "creationTime=" + new Date( creationTime ) +
+                               ",lastAccessTime=" + new Date( lastAccessTime ) +
+                               ",lastWriteTime=" + new Date( lastWriteTime ) +
+                               ",changeTime=" + new Date( changeTime ) +
+                               ",attributes=0x" + Log.getHexString( attributes, 4 ) + "]" );
+               }
+       }
+       class SmbQueryFileStandardInfo implements Info {
+               long allocationSize;
+               long endOfFile;
+               int numberOfLinks;
+               boolean deletePending;
+               boolean directory;
+
+               public int getAttributes() {
+                       return 0;
+               }
+               public long getLastWriteTime() {
+                       return 0;
+               }
+               public long getSize() {
+                       return endOfFile;
+               }
+               public String toString() {
+                       return new String( "SmbQueryInfoStandard[" +
+                               "allocationSize=" + allocationSize +
+                               ",endOfFile=" + endOfFile +
+                               ",numberOfLinks=" + numberOfLinks +
+                               ",deletePending=" + deletePending +
+                               ",directory=" + directory + "]" );
+               }
+       }
+
+       int informationLevel;
+       Info info;
+
+       Trans2QueryPathInformationResponse( int informationLevel ) {
+               this.informationLevel = informationLevel;
+               subCommand = SmbComTransaction.TRANS2_QUERY_PATH_INFORMATION;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               // observed two zero bytes here with at least win98
+               return 2;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               switch( informationLevel ) {
+                       case SMB_QUERY_FILE_BASIC_INFO:
+                               return readSmbQueryFileBasicInfoWireFormat( buffer, bufferIndex );
+                       case SMB_QUERY_FILE_STANDARD_INFO:
+                               return readSmbQueryFileStandardInfoWireFormat( buffer, bufferIndex );
+                       default:
+                               return 0;
+               }
+       }
+       int readSmbQueryFileStandardInfoWireFormat( byte[] buffer, int bufferIndex ) {
+               int start = bufferIndex;
+
+               SmbQueryFileStandardInfo info = new SmbQueryFileStandardInfo();
+               info.allocationSize = readLong( buffer, bufferIndex );
+               bufferIndex += 8;
+               info.endOfFile = readLong( buffer, bufferIndex );
+               bufferIndex += 8;
+               info.numberOfLinks = readInt4( buffer, bufferIndex );
+               bufferIndex += 4;
+               info.deletePending = ( buffer[bufferIndex++] & 0xFF ) > 0;
+               info.directory = ( buffer[bufferIndex++] & 0xFF ) > 0;
+               this.info = info;
+
+               return bufferIndex - start;
+       }
+       int readSmbQueryFileBasicInfoWireFormat( byte[] buffer, int bufferIndex ) {
+               int start = bufferIndex;
+
+               SmbQueryFileBasicInfo info = new SmbQueryFileBasicInfo();
+               info.creationTime = readTime( buffer, bufferIndex );
+               bufferIndex += 8;
+               info.lastAccessTime = readTime( buffer, bufferIndex );
+               bufferIndex += 8;
+               info.lastWriteTime = readTime( buffer, bufferIndex );
+               bufferIndex += 8;
+               info.changeTime = readTime( buffer, bufferIndex );
+               bufferIndex += 8;
+               info.attributes = readInt2( buffer, bufferIndex );
+               bufferIndex += 2;
+               this.info = info;
+
+               return bufferIndex - start;
+       }
+       public String toString() {
+               return new String( "Trans2QueryPathInformationResponse[" +
+                       super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/TransCallNamedPipe.java b/src/jcifs/smb/TransCallNamedPipe.java
new file mode 100644 (file)
index 0000000..2549cda
--- /dev/null
@@ -0,0 +1,73 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class TransCallNamedPipe extends SmbComTransaction {
+
+       byte[] pipeData;
+       int pipeDataOff, pipeDataLen;
+
+       TransCallNamedPipe( String pipeName, byte[] data, int off, int len ) {
+               name = pipeName;
+               pipeData = data;
+               pipeDataOff = off;
+               pipeDataLen = len;
+               command = SMB_COM_TRANSACTION;
+               subCommand = TRANS_CALL_NAMED_PIPE;
+               timeout = 0xFFFFFFFF;
+               maxParameterCount = 0;
+               maxDataCount = 0xFFFF;
+               maxSetupCount = (byte)0x00;
+               setupCount = 2;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = subCommand;
+               dst[dstIndex++] = (byte)0x00;
+               // this says "Transaction priority" in netmon
+               dst[dstIndex++] = (byte)0x00; // no FID
+               dst[dstIndex++] = (byte)0x00;
+               return 4;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               if(( dst.length - dstIndex ) < pipeDataLen ) {
+                       Log.println( Log.WARNINGS, "smb warning",
+                                                       "TransCallNamedPipe data too long for buffer" );
+                       return 0;
+               }
+               System.arraycopy( pipeData, pipeDataOff, dst, dstIndex, pipeDataLen );
+               return pipeDataLen;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "TransCallNamedPipe[" + super.toString() +
+                       ",pipeName=" + name + "]" );
+       }
+}
diff --git a/src/jcifs/smb/TransCallNamedPipeResponse.java b/src/jcifs/smb/TransCallNamedPipeResponse.java
new file mode 100644 (file)
index 0000000..1b8fbe6
--- /dev/null
@@ -0,0 +1,57 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class TransCallNamedPipeResponse extends SmbComTransactionResponse {
+
+       SmbNamedPipe pipe;
+
+       TransCallNamedPipeResponse( SmbNamedPipe pipe ) {
+               this.pipe = pipe;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               if( pipe.pipeIn != null ) {
+                       TransactNamedPipeInputStream in = (TransactNamedPipeInputStream)pipe.pipeIn;
+                       synchronized( in.lock ) {
+                               in.receive( buffer, bufferIndex, len );
+                               in.lock.notify();
+                       }
+               }
+               return len;
+       }
+       public String toString() {
+               return new String( "TransCallNamedPipeResponse[" + super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/TransTransactNamedPipe.java b/src/jcifs/smb/TransTransactNamedPipe.java
new file mode 100644 (file)
index 0000000..2c5cebc
--- /dev/null
@@ -0,0 +1,72 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class TransTransactNamedPipe extends SmbComTransaction {
+
+       byte[] pipeData;
+       int pipeFid, pipeDataOff, pipeDataLen;
+
+       TransTransactNamedPipe( int fid, byte[] data, int off, int len ) {
+               pipeFid = fid;
+               pipeData = data;
+               pipeDataOff = off;
+               pipeDataLen = len;
+               command = SMB_COM_TRANSACTION;
+               subCommand = TRANS_TRANSACT_NAMED_PIPE;
+               maxParameterCount = 0;
+               maxDataCount = 0xFFFF;
+               maxSetupCount = (byte)0x00;
+               setupCount = 2;
+               name = "\\PIPE\\";
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = subCommand;
+               dst[dstIndex++] = (byte)0x00;
+               writeInt2( pipeFid, dst, dstIndex );
+               dstIndex += 2;
+               return 4;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               if(( dst.length - dstIndex ) < pipeDataLen ) {
+                       Log.println( Log.WARNINGS, "smb warning",
+                                                       "TransTransactNamedPipe data too long for buffer" );
+                       return 0;
+               }
+               System.arraycopy( pipeData, pipeDataOff, dst, dstIndex, pipeDataLen );
+               return pipeDataLen;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "TransTransactNamedPipe[" + super.toString() +
+                       ",pipeFid=" + pipeFid + "]" );
+       }
+}
diff --git a/src/jcifs/smb/TransTransactNamedPipeResponse.java b/src/jcifs/smb/TransTransactNamedPipeResponse.java
new file mode 100644 (file)
index 0000000..ef5715d
--- /dev/null
@@ -0,0 +1,57 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class TransTransactNamedPipeResponse extends SmbComTransactionResponse {
+
+       SmbNamedPipe pipe;
+
+       TransTransactNamedPipeResponse( SmbNamedPipe pipe ) {
+               this.pipe = pipe;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               if( pipe.pipeIn != null ) {
+                       TransactNamedPipeInputStream in = (TransactNamedPipeInputStream)pipe.pipeIn;
+                       synchronized( in.lock ) {
+                               in.receive( buffer, bufferIndex, len );
+                               in.lock.notify();
+                       }
+               }
+               return len;
+       }
+       public String toString() {
+               return new String( "TransTransactNamedPipeResponse[" + super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/TransWaitNamedPipe.java b/src/jcifs/smb/TransWaitNamedPipe.java
new file mode 100644 (file)
index 0000000..27a8e60
--- /dev/null
@@ -0,0 +1,60 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class TransWaitNamedPipe extends SmbComTransaction {
+
+       TransWaitNamedPipe( String pipeName ) {
+               name = pipeName;
+               command = SMB_COM_TRANSACTION;
+               subCommand = TRANS_WAIT_NAMED_PIPE;
+               timeout = 0xFFFFFFFF;
+               maxParameterCount = 0;
+               maxDataCount = 0;
+               maxSetupCount = (byte)0x00;
+               setupCount = 2;
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               dst[dstIndex++] = subCommand;
+               dst[dstIndex++] = (byte)0x00;
+               dst[dstIndex++] = (byte)0x00; // no FID
+               dst[dstIndex++] = (byte)0x00;
+               return 4;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "TransWaitNamedPipe[" + super.toString() +
+                       ",pipeName=" + name + "]" );
+       }
+}
diff --git a/src/jcifs/smb/TransWaitNamedPipeResponse.java b/src/jcifs/smb/TransWaitNamedPipeResponse.java
new file mode 100644 (file)
index 0000000..47e30a0
--- /dev/null
@@ -0,0 +1,49 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+class TransWaitNamedPipeResponse extends SmbComTransactionResponse {
+
+       // not much to this one is there :~)
+
+       TransWaitNamedPipeResponse() {
+       }
+
+       int writeSetupWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeParametersWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int writeDataWireFormat( byte[] dst, int dstIndex ) {
+               return 0;
+       }
+       int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
+               return 0;
+       }
+       public String toString() {
+               return new String( "TransWaitNamedPipeResponse[" + super.toString() + "]" );
+       }
+}
diff --git a/src/jcifs/smb/TransactNamedPipeInputStream.java b/src/jcifs/smb/TransactNamedPipeInputStream.java
new file mode 100644 (file)
index 0000000..364e4b8
--- /dev/null
@@ -0,0 +1,122 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+class TransactNamedPipeInputStream extends InputStream {
+
+       static final int INIT_PIPE_SIZE = 4096;
+
+       byte[] pipe_buf = new byte[INIT_PIPE_SIZE];
+       int beg_idx, nxt_idx, used;
+       Object lock;
+
+       TransactNamedPipeInputStream() {
+               lock = new Object();
+       }
+       public void close() throws IOException {
+       }
+       public int read() throws IOException {
+               int result = -1;
+
+               synchronized( lock ) {
+                       try {
+                               while( used == 0 ) {
+                                       lock.wait();
+                               }
+                       } catch( InterruptedException ie ) {
+                               throw new IOException( ie.getMessage() );
+                       }
+                       result = pipe_buf[beg_idx] & 0xFF;
+                       beg_idx = ( beg_idx + 1 ) % pipe_buf.length;
+               }
+               return result;
+       }
+       public int read( byte[] b ) throws IOException {
+               return read( b, 0, b.length );
+       }
+       public int read( byte[] b, int off, int len ) throws IOException {
+               int result = -1;
+               int i;
+
+               if( len <= 0 ) {
+                       return 0;
+               }
+               synchronized( lock ) {
+                       try {
+                               while( used == 0 ) {
+                                       lock.wait();
+                               }
+                       } catch( InterruptedException ie ) {
+                               throw new IOException( ie.getMessage() );
+                       }
+                       i = pipe_buf.length - beg_idx;
+                       result = len > used ? used : len;
+                       if( used > i && result > i ) {
+                               System.arraycopy( pipe_buf, beg_idx, b, off, i );
+                               off += i;
+                               System.arraycopy( pipe_buf, 0, b, off, result );
+                       } else {
+                               System.arraycopy( pipe_buf, beg_idx, b, off, result );
+                       }
+                       used -= result;
+                       beg_idx = ( beg_idx + result ) % pipe_buf.length;
+               }
+               return result;
+       }
+
+       int receive( byte[] b, int off, int len ) {
+               int i;
+
+               if( len > ( pipe_buf.length - used )) {
+                       byte[] tmp;
+                       int new_size;
+
+                       new_size = pipe_buf.length * 2;
+                       if( len > ( new_size - used )) {
+                               new_size = len + used;
+                       }
+                       tmp = pipe_buf;
+                       pipe_buf = new byte[new_size];
+                       i = pipe_buf.length - beg_idx;
+                       if( used > i ) {
+                               System.arraycopy( tmp, beg_idx, pipe_buf, 0, i );
+                               System.arraycopy( tmp, 0, pipe_buf, i, used - i ); 
+                       } else {
+                               System.arraycopy( tmp, beg_idx, pipe_buf, 0, used );
+                       }
+                       beg_idx = 0;
+                       tmp = null;
+               }
+
+               i = pipe_buf.length - nxt_idx;
+               if( len > i ) {
+                       System.arraycopy( b, off, pipe_buf, nxt_idx, i );
+                       off += i;
+                       System.arraycopy( b, off, pipe_buf, 0, len - i ); 
+               } else {
+                       System.arraycopy( b, off, pipe_buf, nxt_idx, len );
+               }
+               nxt_idx = ( nxt_idx + len ) % pipe_buf.length;
+               used += len;
+               return len;
+       }
+}
diff --git a/src/jcifs/smb/TransactNamedPipeOutputStream.java b/src/jcifs/smb/TransactNamedPipeOutputStream.java
new file mode 100644 (file)
index 0000000..e5fdf6e
--- /dev/null
@@ -0,0 +1,62 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+class TransactNamedPipeOutputStream extends OutputStream {
+
+       String path;
+       SmbNamedPipe pipe;
+       byte[] tmp = new byte[1];
+       
+       TransactNamedPipeOutputStream( SmbNamedPipe pipe ) throws IOException {
+               this.pipe = pipe;
+               path = pipe.path.toUpperCase();
+       }
+
+       public void close() throws IOException {
+       }
+       public void write( int b ) throws IOException {
+               tmp[0] = (byte)b;
+               write( tmp, 0, 1 );
+       }
+       public void write( byte[] b ) throws IOException {
+               write( b, 0, b.length );
+       }
+       public void write( byte[] b, int off, int len ) throws IOException {
+               if( len < 0 ) {
+                       len = 0;
+               }
+
+               if(( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_CALL ) ==
+                                                                                                       SmbNamedPipe.PIPE_TYPE_CALL ) {
+                       pipe.tree.sendTransaction( new TransWaitNamedPipe( path ),
+                                                                               new TransWaitNamedPipeResponse() );
+                       pipe.tree.sendTransaction( new TransCallNamedPipe( path, b, off, len ),
+                                                                               new TransCallNamedPipeResponse( pipe ));
+               } else if(( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_TRANSACT ) ==
+                                                                                                       SmbNamedPipe.PIPE_TYPE_TRANSACT ) {
+                       pipe.open(( pipe.pipeType & 0xFF0000 ) | SmbFile.O_EXCL );
+                       pipe.tree.sendTransaction( new TransTransactNamedPipe( pipe.fid, b, off, len ),
+                                                                               new TransTransactNamedPipeResponse( pipe ));
+               }
+       }
+}
diff --git a/src/jcifs/util/Config.java b/src/jcifs/util/Config.java
new file mode 100644 (file)
index 0000000..8c7d979
--- /dev/null
@@ -0,0 +1,211 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.util;
+
+import java.util.Properties;
+import java.util.Enumeration;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * This class uses a static {@link jcifs.util.PropertiesTree} to act
+ * as a cental repository of configuration information. It cannot be
+ * instantiated. Similar to <code>System</code> properties the namespace
+ * is global therefore property names should be unique. Before use,
+ * the <code>load</code> method should be called with the name of a
+ * <code>PropertiesTree</code> file(or <code>null</code> indicating no
+ * file) to initialize the <code>Config</code>. The <code>System</code>
+ * properties will then populate the <code>Config</code> as well potentially
+ * overwriting properties from the file. Thus properties provided on the
+ * commandline with the <code>-Dproperty.name=value</code> VM parameter
+ * will override properties from the configuration file.
+ */
+
+public class Config {
+
+       // supress javadoc constructor summary by removing 'protected'
+       Config() {}
+
+       /**
+        * The static <code>PropertiesTree</code>.
+        */
+
+       protected static PropertiesTree properties = new PropertiesTree();
+
+       /**
+        * Load the <code>Config</code> with properties from the stream
+        * <code>in</code> which should be in <code>PropertiesTree</code>
+        * format. See <a href="../../../properties.html">More About
+        * PropertiesTree and it's File Format</code>.
+        */
+
+       public static void load( InputStream in ) throws IOException {
+               Properties sys;
+
+               if( in != null ) {
+                       properties.load( in );
+               }
+
+               sys = System.getProperties();
+               for( Enumeration e = sys.propertyNames(); e.hasMoreElements(); ) {
+                       String key = (String)e.nextElement();
+                       String val = (String)sys.getProperty( key );
+                       if( key != null && val != null ) {
+                               try {
+                                       properties.put( key, val );
+                               } catch( IllegalArgumentException iae ) {
+                               }
+                       }
+               }
+       }
+
+       /**
+        * List the properties in the <code>Code</code>.
+        */
+
+       public static void list( PrintStream out ) throws IOException {
+               properties.list( out );
+       }
+
+       /**
+        * Add a property. If the property already
+        * exists and it is a <code>PropertiesTree</code> an
+        * <code>IllegalArgumentException</code> will be thrown to indicate
+        * that an entire branch of the tree cannot be overwritten. If
+        * however the node is a leaf property, it will be overwritten
+        * and the old value returned as a <code>String</code>.
+        */
+
+       public static String setProperty( String key, String value ) {
+               return (String)properties.put( key, value );
+       }
+
+       /**
+        * Retrieve a property as an <code>Object</code>. Possible
+        * types are <code>String</code> if the property is a leaf node,
+        * or a <code>PropertiesTree</code> if key resolves to a parent node,
+        * or <code>null</code> otherwise.
+        */
+
+       public static Object get( String key ) {
+               return properties.get( key );
+       }
+
+       /**
+        * Retrieve a <code>String</code>. If the key cannot be found,
+        * the provided <code>def</code> default parameter will be returned.
+        */
+
+       public static String getProperty( String key, String def ) {
+               String result = null;
+               Object obj = get( key );
+               if( obj != null && obj instanceof String ) {
+                       result = (String)obj;
+               }
+               return obj == null ? def : result;
+       }
+
+       /**
+        * Retrieve a <code>String</code>. If the property is not found, <code>null</code> is returned.
+        */
+
+       public static String getProperty( String key ) {
+               String result = null;
+               Object obj = get( key );
+               if( obj != null && obj instanceof String ) {
+                       result = (String)obj;
+               }
+               return result;
+       }
+
+       /**
+        * Retrieve an <code>int</code>. If the key does not exist or
+        * cannot be converted to an <code>int</code>, the provided default
+        * argument will be returned.
+        */
+
+       public static int getInt( String key, int def ) {
+               Object obj = get( key );
+               if( obj != null && obj instanceof String ) {
+                       try {
+                               def = Integer.parseInt( (String)obj );
+                       } catch( NumberFormatException nfe ) {
+                               Log.printStackTrace( "configuration warning", nfe );
+                       }
+               }
+               return def;
+       }
+
+       /**
+        * Retrieve an <code>int</code>. If the property is not found, <code>-1</code> is returned.
+        */
+
+       public static int getInt( String key ) {
+               int result = -1;
+               Object obj = get( key );
+               if( obj != null && obj instanceof String ) {
+                       try {
+                               result = Integer.parseInt( (String)obj );
+                       } catch( NumberFormatException nfe ) {
+                               Log.printStackTrace( "configuration warning", nfe );
+                       }
+               }
+               return result;
+       }
+
+       /** 
+        * Retrieve an <code>InetAddress</code>. If the address is not
+        * an IP address and cannot be resolved <code>null</code> will
+        * be returned.
+        */
+
+       public static InetAddress getInetAddress( String key, InetAddress def ) {
+               String addr = getProperty( key );
+               if( addr != null ) {
+                       try {
+                               def = InetAddress.getByName( addr );
+                       } catch( UnknownHostException uhe ) {
+                       }
+               }
+               return def;
+       }
+
+       /**
+        * Retrieve a boolean value. If the property is not found, the value of <code>def</code> is returned.
+        */
+
+       public static boolean getBoolean( String key, boolean def ) {
+               String b = getProperty( key );
+               if( b != null ) {
+                       def = b.toLowerCase().equals( "true" );
+               }
+               return def;
+       }
+
+       /**
+        * Print all properties through the {@link jcifs.util.Log} class with the mask <code>Log.WARNINGS</code>.
+        */
+
+       public static void printProperties( String msg ) {
+               Log.printProperties( Log.WARNINGS, msg, properties );
+       }
+}
diff --git a/src/jcifs/util/DES.java b/src/jcifs/util/DES.java
new file mode 100644 (file)
index 0000000..08a47b3
--- /dev/null
@@ -0,0 +1,551 @@
+// DesCipher - the DES encryption method
+//
+// The meat of this code is by Dave Zimmerman <dzimm@widget.com>, and is:
+//
+// Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
+//
+// Permission to use, copy, modify, and distribute this software
+// and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
+// without fee is hereby granted, provided that this copyright notice is kept
+// intact.
+//
+// WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
+// OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+// PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE
+// FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+// DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
+//
+// THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
+// CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
+// PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
+// NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
+// SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
+// SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
+// PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES").  WIDGET WORKSHOP
+// SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
+// HIGH RISK ACTIVITIES.
+//
+//
+// The rest is:
+//
+// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>.  All rights reserved.
+//
+// Copyright (C) 1996 by Wolfgang Platzer
+// email: wplatzer@iaik.tu-graz.ac.at
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+
+package jcifs.util;
+
+import java.io.*;
+
+/**
+ * This code is derived from the above source
+ * JCIFS API
+ * Norbert Hranitzky
+ *
+ * <p>and modified again by Michael B. Allen
+ */
+
+public class DES   {
+
+
+    private int[] encryptKeys = new int[32];
+    private int[] decryptKeys = new int[32];
+
+    private int[] tempInts = new int[2];
+
+
+    public DES( ) {
+
+    }
+
+    // Constructor, byte-array key.
+    public DES( byte[] key )   {
+               if( key.length == 7 ) {
+                       byte[] key8 = new byte[8];
+                       makeSMBKey( key, key8 );
+                       setKey( key8 );
+               } else {
+               setKey( key );
+               }
+       }
+
+
+    public static void makeSMBKey(byte[] key7, byte[] key8) {
+
+           int i;
+
+           key8[0] = (byte) ( ( key7[0] >> 1) & 0xff);
+           key8[1] = (byte)(( ((key7[0] & 0x01) << 6) | (((key7[1] & 0xff)>>2) & 0xff)) & 0xff );
+           key8[2] = (byte)(( ((key7[1] & 0x03) << 5) | (((key7[2] & 0xff)>>3) & 0xff)) & 0xff );
+           key8[3] = (byte)(( ((key7[2] & 0x07) << 4) | (((key7[3] & 0xff)>>4) & 0xff)) & 0xff );
+           key8[4] = (byte)(( ((key7[3] & 0x0F) << 3) | (((key7[4] & 0xff)>>5) & 0xff)) & 0xff );
+           key8[5] = (byte)(( ((key7[4] & 0x1F) << 2) | (((key7[5] & 0xff)>>6) & 0xff)) & 0xff );
+           key8[6] = (byte)(( ((key7[5] & 0x3F) << 1) | (((key7[6] & 0xff)>>7) & 0xff)) & 0xff );
+           key8[7] = (byte)(key7[6] & 0x7F);
+           for (i=0;i<8;i++) {
+                   key8[i] = (byte)( key8[i] << 1);
+           }
+    }
+
+    /// Set the key.
+    public void setKey( byte[] key ) {
+
+           // CHECK PAROTY TBD
+           deskey( key, true, encryptKeys );
+           deskey( key, false, decryptKeys );
+       }
+
+    // Turn an 8-byte key into internal keys.
+    private void deskey( byte[] keyBlock, boolean encrypting, int[] KnL ) {
+
+           int i, j, l, m, n;
+           int[] pc1m = new int[56];
+           int[] pcr  = new int[56];
+           int[] kn   = new int[32];
+
+           for ( j = 0; j < 56; ++j )  {
+               l       = pc1[j];
+               m       = l & 07;
+               pc1m[j] = ( (keyBlock[l >>> 3] & bytebit[m]) != 0 )? 1: 0;
+           }
+
+           for ( i = 0; i < 16; ++i ) {
+
+               if ( encrypting )
+                       m = i << 1;
+               else
+                       m = (15-i) << 1;
+               n = m+1;
+               kn[m] = kn[n] = 0;
+               for ( j = 0; j < 28; ++j ) {
+                       l = j+totrot[i];
+                       if ( l < 28 )
+                           pcr[j] = pc1m[l];
+                       else
+                           pcr[j] = pc1m[l-28];
+                   }
+               for ( j=28; j < 56; ++j ) {
+                       l = j+totrot[i];
+                       if ( l < 56 )
+                           pcr[j] = pc1m[l];
+                       else
+                           pcr[j] = pc1m[l-28];
+                   }
+               for ( j = 0; j < 24; ++j ) {
+                       if ( pcr[pc2[j]] != 0 )
+                           kn[m] |= bigbyte[j];
+                       if ( pcr[pc2[j+24]] != 0 )
+                           kn[n] |= bigbyte[j];
+                   }
+           }
+           cookey( kn, KnL );
+       }
+
+    private void cookey( int[] raw, int KnL[] )        {
+           int raw0, raw1;
+           int rawi, KnLi;
+           int i;
+
+           for ( i = 0, rawi = 0, KnLi = 0; i < 16; ++i )   {
+               raw0 = raw[rawi++];
+               raw1 = raw[rawi++];
+               KnL[KnLi]  = (raw0 & 0x00fc0000) <<   6;
+               KnL[KnLi] |= (raw0 & 0x00000fc0) <<  10;
+               KnL[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
+               KnL[KnLi] |= (raw1 & 0x00000fc0) >>>  6;
+               ++KnLi;
+               KnL[KnLi]  = (raw0 & 0x0003f000) <<  12;
+               KnL[KnLi] |= (raw0 & 0x0000003f) <<  16;
+               KnL[KnLi] |= (raw1 & 0x0003f000) >>>  4;
+               KnL[KnLi] |= (raw1 & 0x0000003f);
+               ++KnLi;
+           }
+       }
+
+
+    /// Encrypt a block of eight bytes.
+    private void encrypt( byte[] clearText, int clearOff, byte[] cipherText, int cipherOff ) {
+
+           squashBytesToInts( clearText, clearOff, tempInts, 0, 2 );
+           des( tempInts, tempInts, encryptKeys );
+           spreadIntsToBytes( tempInts, 0, cipherText, cipherOff, 2 );
+       }
+
+    /// Decrypt a block of eight bytes.
+    private void decrypt( byte[] cipherText, int cipherOff, byte[] clearText, int clearOff ) {
+
+           squashBytesToInts( cipherText, cipherOff, tempInts, 0, 2 );
+           des( tempInts, tempInts, decryptKeys );
+           spreadIntsToBytes( tempInts, 0, clearText, clearOff, 2 );
+       }
+
+    // The DES function.
+    private void des( int[] inInts, int[] outInts, int[] keys ) {
+
+           int fval, work, right, leftt;
+           int round;
+           int keysi = 0;
+
+           leftt = inInts[0];
+           right = inInts[1];
+
+           work   = ((leftt >>>  4) ^ right) & 0x0f0f0f0f;
+           right ^= work;
+           leftt ^= (work << 4);
+
+           work   = ((leftt >>> 16) ^ right) & 0x0000ffff;
+           right ^= work;
+           leftt ^= (work << 16);
+
+           work   = ((right >>>  2) ^ leftt) & 0x33333333;
+           leftt ^= work;
+           right ^= (work << 2);
+
+           work   = ((right >>>  8) ^ leftt) & 0x00ff00ff;
+           leftt ^= work;
+           right ^= (work << 8);
+           right  = (right << 1) | ((right >>> 31) & 1);
+
+           work   = (leftt ^ right) & 0xaaaaaaaa;
+           leftt ^= work;
+           right ^= work;
+           leftt  = (leftt << 1) | ((leftt >>> 31) & 1);
+
+           for ( round = 0; round < 8; ++round )  {
+               work   = (right << 28) | (right >>> 4);
+               work  ^= keys[keysi++];
+               fval   = SP7[ work             & 0x0000003f ];
+               fval  |= SP5[(work >>>  8) & 0x0000003f ];
+               fval  |= SP3[(work >>> 16) & 0x0000003f ];
+               fval  |= SP1[(work >>> 24) & 0x0000003f ];
+               work   = right ^ keys[keysi++];
+               fval  |= SP8[ work         & 0x0000003f ];
+               fval  |= SP6[(work >>>  8) & 0x0000003f ];
+               fval  |= SP4[(work >>> 16) & 0x0000003f ];
+               fval  |= SP2[(work >>> 24) & 0x0000003f ];
+               leftt ^= fval;
+               work   = (leftt << 28) | (leftt >>> 4);
+               work  ^= keys[keysi++];
+               fval   = SP7[ work             & 0x0000003f ];
+               fval  |= SP5[(work >>>  8) & 0x0000003f ];
+               fval  |= SP3[(work >>> 16) & 0x0000003f ];
+               fval  |= SP1[(work >>> 24) & 0x0000003f ];
+               work   = leftt ^ keys[keysi++];
+               fval  |= SP8[ work             & 0x0000003f ];
+               fval  |= SP6[(work >>>  8) & 0x0000003f ];
+               fval  |= SP4[(work >>> 16) & 0x0000003f ];
+               fval  |= SP2[(work >>> 24) & 0x0000003f ];
+               right ^= fval;
+           }
+
+           right  = (right << 31) | (right >>> 1);
+           work   = (leftt ^ right) & 0xaaaaaaaa;
+           leftt ^= work;
+           right ^= work;
+           leftt  = (leftt << 31) | (leftt >>> 1);
+           work   = ((leftt >>>  8) ^ right) & 0x00ff00ff;
+           right ^= work;
+           leftt ^= (work << 8);
+           work   = ((leftt >>>  2) ^ right) & 0x33333333;
+           right ^= work;
+           leftt ^= (work << 2);
+           work   = ((right >>> 16) ^ leftt) & 0x0000ffff;
+           leftt ^= work;
+           right ^= (work << 16);
+           work   = ((right >>>  4) ^ leftt) & 0x0f0f0f0f;
+           leftt ^= work;
+           right ^= (work << 4);
+           outInts[0] = right;
+           outInts[1] = leftt;
+       }
+
+
+       /// Encrypt a block of bytes.
+    public void encrypt( byte[] clearText, byte[] cipherText )         {
+           encrypt( clearText, 0, cipherText, 0 );
+       }
+
+    /// Decrypt a block of bytes.
+    public void decrypt( byte[] cipherText, byte[] clearText ) {
+
+           decrypt( cipherText, 0, clearText, 0 );
+       }
+
+    /**
+     * encrypts an array where the length must be a multiple of 8
+     */
+    public byte[] encrypt(byte[] clearText) {
+
+        int length = clearText.length;
+
+        if (length % 8 != 0) {
+            System.out.println("Array must be a multiple of 8");
+            return null;
+        }
+
+        byte[] cipherText = new byte[length];
+        int count = length / 8;
+
+        for (int i=0; i<count; i++)
+            encrypt(clearText, i*8, cipherText, i*8);
+
+        return cipherText;
+    }
+
+    /**
+     * decrypts an array where the length must be a multiple of 8
+     */
+    public byte[] decrypt(byte[] cipherText) {
+
+        int length = cipherText.length;
+
+        if (length % 8 != 0) {
+            System.out.println("Array must be a multiple of 8");
+            return null;
+        }
+
+        byte[] clearText = new byte[length];
+        int count = length / 8;
+
+        for (int i=0; i<count; i++)
+            encrypt(cipherText, i*8, clearText, i*8);
+
+        return clearText;
+    }
+
+
+    // Tables, permutations, S-boxes, etc.
+
+    private static byte[] bytebit = {
+           (byte)0x80, (byte)0x40, (byte)0x20, (byte)0x10,
+           (byte)0x08, (byte)0x04, (byte)0x02, (byte)0x01
+       };
+    private static int[] bigbyte = {
+           0x800000, 0x400000, 0x200000, 0x100000,
+           0x080000, 0x040000, 0x020000, 0x010000,
+           0x008000, 0x004000, 0x002000, 0x001000,
+           0x000800, 0x000400, 0x000200, 0x000100,
+           0x000080, 0x000040, 0x000020, 0x000010,
+           0x000008, 0x000004, 0x000002, 0x000001
+       };
+    private static byte[] pc1 = {
+        (byte)56, (byte)48, (byte)40, (byte)32, (byte)24, (byte)16, (byte) 8,
+        (byte) 0, (byte)57, (byte)49, (byte)41, (byte)33, (byte)25, (byte)17,
+           (byte) 9, (byte) 1, (byte)58, (byte)50, (byte)42, (byte)34, (byte)26,
+        (byte)18, (byte)10, (byte) 2, (byte)59, (byte)51, (byte)43, (byte)35,
+           (byte)62, (byte)54, (byte)46, (byte)38, (byte)30, (byte)22, (byte)14,
+        (byte) 6, (byte)61, (byte)53, (byte)45, (byte)37, (byte)29, (byte)21,
+           (byte)13, (byte) 5, (byte)60, (byte)52, (byte)44, (byte)36, (byte)28,
+        (byte)20, (byte)12, (byte) 4, (byte)27, (byte)19, (byte)11, (byte)3
+       };
+    private static int[] totrot = {
+        1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
+       };
+
+    private static byte[] pc2 = {
+           (byte)13, (byte)16, (byte)10, (byte)23, (byte) 0, (byte) 4,
+           (byte) 2, (byte)27, (byte)14, (byte) 5, (byte)20, (byte) 9,
+           (byte)22, (byte)18, (byte)11, (byte)3 , (byte)25, (byte) 7,
+           (byte)15, (byte) 6, (byte)26, (byte)19, (byte)12, (byte) 1,
+           (byte)40, (byte)51, (byte)30, (byte)36, (byte)46, (byte)54,
+           (byte)29, (byte)39, (byte)50, (byte)44, (byte)32, (byte)47,
+           (byte)43, (byte)48, (byte)38, (byte)55, (byte)33, (byte)52,
+           (byte)45, (byte)41, (byte)49, (byte)35, (byte)28, (byte)31,
+       };
+
+    private static int[] SP1 = {
+        0x01010400, 0x00000000, 0x00010000, 0x01010404,
+           0x01010004, 0x00010404, 0x00000004, 0x00010000,
+           0x00000400, 0x01010400, 0x01010404, 0x00000400,
+           0x01000404, 0x01010004, 0x01000000, 0x00000004,
+           0x00000404, 0x01000400, 0x01000400, 0x00010400,
+           0x00010400, 0x01010000, 0x01010000, 0x01000404,
+           0x00010004, 0x01000004, 0x01000004, 0x00010004,
+           0x00000000, 0x00000404, 0x00010404, 0x01000000,
+           0x00010000, 0x01010404, 0x00000004, 0x01010000,
+           0x01010400, 0x01000000, 0x01000000, 0x00000400,
+           0x01010004, 0x00010000, 0x00010400, 0x01000004,
+           0x00000400, 0x00000004, 0x01000404, 0x00010404,
+           0x01010404, 0x00010004, 0x01010000, 0x01000404,
+           0x01000004, 0x00000404, 0x00010404, 0x01010400,
+           0x00000404, 0x01000400, 0x01000400, 0x00000000,
+           0x00010004, 0x00010400, 0x00000000, 0x01010004
+       };
+    private static int[] SP2 = {
+           0x80108020, 0x80008000, 0x00008000, 0x00108020,
+           0x00100000, 0x00000020, 0x80100020, 0x80008020,
+           0x80000020, 0x80108020, 0x80108000, 0x80000000,
+           0x80008000, 0x00100000, 0x00000020, 0x80100020,
+           0x00108000, 0x00100020, 0x80008020, 0x00000000,
+           0x80000000, 0x00008000, 0x00108020, 0x80100000,
+           0x00100020, 0x80000020, 0x00000000, 0x00108000,
+           0x00008020, 0x80108000, 0x80100000, 0x00008020,
+           0x00000000, 0x00108020, 0x80100020, 0x00100000,
+           0x80008020, 0x80100000, 0x80108000, 0x00008000,
+           0x80100000, 0x80008000, 0x00000020, 0x80108020,
+           0x00108020, 0x00000020, 0x00008000, 0x80000000,
+           0x00008020, 0x80108000, 0x00100000, 0x80000020,
+           0x00100020, 0x80008020, 0x80000020, 0x00100020,
+           0x00108000, 0x00000000, 0x80008000, 0x00008020,
+           0x80000000, 0x80100020, 0x80108020, 0x00108000
+       };
+    private static int[] SP3 = {
+           0x00000208, 0x08020200, 0x00000000, 0x08020008,
+           0x08000200, 0x00000000, 0x00020208, 0x08000200,
+           0x00020008, 0x08000008, 0x08000008, 0x00020000,
+           0x08020208, 0x00020008, 0x08020000, 0x00000208,
+           0x08000000, 0x00000008, 0x08020200, 0x00000200,
+           0x00020200, 0x08020000, 0x08020008, 0x00020208,
+           0x08000208, 0x00020200, 0x00020000, 0x08000208,
+           0x00000008, 0x08020208, 0x00000200, 0x08000000,
+           0x08020200, 0x08000000, 0x00020008, 0x00000208,
+           0x00020000, 0x08020200, 0x08000200, 0x00000000,
+           0x00000200, 0x00020008, 0x08020208, 0x08000200,
+           0x08000008, 0x00000200, 0x00000000, 0x08020008,
+           0x08000208, 0x00020000, 0x08000000, 0x08020208,
+           0x00000008, 0x00020208, 0x00020200, 0x08000008,
+           0x08020000, 0x08000208, 0x00000208, 0x08020000,
+           0x00020208, 0x00000008, 0x08020008, 0x00020200
+       };
+    private static int[] SP4 = {
+           0x00802001, 0x00002081, 0x00002081, 0x00000080,
+           0x00802080, 0x00800081, 0x00800001, 0x00002001,
+           0x00000000, 0x00802000, 0x00802000, 0x00802081,
+           0x00000081, 0x00000000, 0x00800080, 0x00800001,
+           0x00000001, 0x00002000, 0x00800000, 0x00802001,
+           0x00000080, 0x00800000, 0x00002001, 0x00002080,
+           0x00800081, 0x00000001, 0x00002080, 0x00800080,
+           0x00002000, 0x00802080, 0x00802081, 0x00000081,
+           0x00800080, 0x00800001, 0x00802000, 0x00802081,
+           0x00000081, 0x00000000, 0x00000000, 0x00802000,
+           0x00002080, 0x00800080, 0x00800081, 0x00000001,
+           0x00802001, 0x00002081, 0x00002081, 0x00000080,
+           0x00802081, 0x00000081, 0x00000001, 0x00002000,
+           0x00800001, 0x00002001, 0x00802080, 0x00800081,
+           0x00002001, 0x00002080, 0x00800000, 0x00802001,
+           0x00000080, 0x00800000, 0x00002000, 0x00802080
+       };
+    private static int[] SP5 = {
+           0x00000100, 0x02080100, 0x02080000, 0x42000100,
+           0x00080000, 0x00000100, 0x40000000, 0x02080000,
+           0x40080100, 0x00080000, 0x02000100, 0x40080100,
+           0x42000100, 0x42080000, 0x00080100, 0x40000000,
+           0x02000000, 0x40080000, 0x40080000, 0x00000000,
+           0x40000100, 0x42080100, 0x42080100, 0x02000100,
+           0x42080000, 0x40000100, 0x00000000, 0x42000000,
+           0x02080100, 0x02000000, 0x42000000, 0x00080100,
+           0x00080000, 0x42000100, 0x00000100, 0x02000000,
+           0x40000000, 0x02080000, 0x42000100, 0x40080100,
+           0x02000100, 0x40000000, 0x42080000, 0x02080100,
+           0x40080100, 0x00000100, 0x02000000, 0x42080000,
+           0x42080100, 0x00080100, 0x42000000, 0x42080100,
+           0x02080000, 0x00000000, 0x40080000, 0x42000000,
+           0x00080100, 0x02000100, 0x40000100, 0x00080000,
+           0x00000000, 0x40080000, 0x02080100, 0x40000100
+       };
+    private static int[] SP6 = {
+           0x20000010, 0x20400000, 0x00004000, 0x20404010,
+           0x20400000, 0x00000010, 0x20404010, 0x00400000,
+           0x20004000, 0x00404010, 0x00400000, 0x20000010,
+           0x00400010, 0x20004000, 0x20000000, 0x00004010,
+           0x00000000, 0x00400010, 0x20004010, 0x00004000,
+           0x00404000, 0x20004010, 0x00000010, 0x20400010,
+           0x20400010, 0x00000000, 0x00404010, 0x20404000,
+           0x00004010, 0x00404000, 0x20404000, 0x20000000,
+           0x20004000, 0x00000010, 0x20400010, 0x00404000,
+           0x20404010, 0x00400000, 0x00004010, 0x20000010,
+           0x00400000, 0x20004000, 0x20000000, 0x00004010,
+           0x20000010, 0x20404010, 0x00404000, 0x20400000,
+           0x00404010, 0x20404000, 0x00000000, 0x20400010,
+           0x00000010, 0x00004000, 0x20400000, 0x00404010,
+           0x00004000, 0x00400010, 0x20004010, 0x00000000,
+           0x20404000, 0x20000000, 0x00400010, 0x20004010
+       };
+    private static int[] SP7 = {
+           0x00200000, 0x04200002, 0x04000802, 0x00000000,
+           0x00000800, 0x04000802, 0x00200802, 0x04200800,
+           0x04200802, 0x00200000, 0x00000000, 0x04000002,
+           0x00000002, 0x04000000, 0x04200002, 0x00000802,
+           0x04000800, 0x00200802, 0x00200002, 0x04000800,
+           0x04000002, 0x04200000, 0x04200800, 0x00200002,
+           0x04200000, 0x00000800, 0x00000802, 0x04200802,
+           0x00200800, 0x00000002, 0x04000000, 0x00200800,
+           0x04000000, 0x00200800, 0x00200000, 0x04000802,
+           0x04000802, 0x04200002, 0x04200002, 0x00000002,
+           0x00200002, 0x04000000, 0x04000800, 0x00200000,
+           0x04200800, 0x00000802, 0x00200802, 0x04200800,
+           0x00000802, 0x04000002, 0x04200802, 0x04200000,
+           0x00200800, 0x00000000, 0x00000002, 0x04200802,
+           0x00000000, 0x00200802, 0x04200000, 0x00000800,
+           0x04000002, 0x04000800, 0x00000800, 0x00200002
+       };
+    private static int[] SP8 = {
+           0x10001040, 0x00001000, 0x00040000, 0x10041040,
+           0x10000000, 0x10001040, 0x00000040, 0x10000000,
+           0x00040040, 0x10040000, 0x10041040, 0x00041000,
+           0x10041000, 0x00041040, 0x00001000, 0x00000040,
+           0x10040000, 0x10000040, 0x10001000, 0x00001040,
+           0x00041000, 0x00040040, 0x10040040, 0x10041000,
+           0x00001040, 0x00000000, 0x00000000, 0x10040040,
+           0x10000040, 0x10001000, 0x00041040, 0x00040000,
+           0x00041040, 0x00040000, 0x10041000, 0x00001000,
+           0x00000040, 0x10040040, 0x00001000, 0x00041040,
+           0x10001000, 0x00000040, 0x10000040, 0x10040000,
+           0x10040040, 0x10000000, 0x00040000, 0x10001040,
+           0x00000000, 0x10041040, 0x00040040, 0x10000040,
+           0x10040000, 0x10001000, 0x10001040, 0x00000000,
+           0x10041040, 0x00041000, 0x00041000, 0x00001040,
+           0x00001040, 0x00040040, 0x10000000, 0x10041000
+       };
+
+
+ /// Squash bytes down to ints.
+    public static void squashBytesToInts( byte[] inBytes, int inOff, int[] outInts,
+                                           int outOff, int intLen ) {
+
+           for ( int i = 0; i < intLen; ++i )
+               outInts[outOff + i] =
+                       ( ( inBytes[inOff + i * 4    ] & 0xff ) << 24 ) |
+                       ( ( inBytes[inOff + i * 4 + 1] & 0xff ) << 16 ) |
+                       ( ( inBytes[inOff + i * 4 + 2] & 0xff ) <<  8 ) |
+                        ( inBytes[inOff + i * 4 + 3] & 0xff );
+    }
+
+    /// Spread ints into bytes.
+    public static void spreadIntsToBytes( int[] inInts, int inOff, byte[] outBytes,
+                                         int outOff, int intLen ) {
+
+           for ( int i = 0; i < intLen; ++i ) {
+
+               outBytes[outOff + i * 4    ] = (byte) ( inInts[inOff + i] >>> 24 );
+               outBytes[outOff + i * 4 + 1] = (byte) ( inInts[inOff + i] >>> 16 );
+               outBytes[outOff + i * 4 + 2] = (byte) ( inInts[inOff + i] >>>  8 );
+               outBytes[outOff + i * 4 + 3] = (byte)   inInts[inOff + i];
+           }
+    }
+}
diff --git a/src/jcifs/util/Log.java b/src/jcifs/util/Log.java
new file mode 100644 (file)
index 0000000..483277c
--- /dev/null
@@ -0,0 +1,439 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ *                     "Christopher R. Hertel" <crh@nts.umn.edu>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.util;
+
+import java.io.Writer;
+import java.io.OutputStream;
+import java.util.Properties;
+
+/**
+ * This log utility uses a combination of bit mask control and io stream
+ * functionality. All methods check the mask with the mask passed as a
+ * parameter to see if any further worki (logging) should be performed. This
+ * provides explicit control at runtime over what is logged. The IO stream
+ * model allows the {@link java.io.PrintWriter} to be set and provides
+ * many of the common {@link java.io.PrintWriter} methods that are usefull
+ * for streams.
+ *
+ * <p>Three example log entries follow:
+ *
+ * <blockquote><pre>
+ * Jul 7 19:17:40.999 - smb tree connect warning 
+ *  path=\\140.240.194.37\IPC$
+ * Jul 7 19:17:41.069 - datagram packet sent to: cranes.campus.foo.br/140.240.194.37
+ * 00000: 00 06 01 10 00 01 00 00 00 00 00 00 20 43 4B 41  |............ CKA|
+ * 00010: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41  |AAAAAAAAAAAAAAAA|
+ * 00020: 41 41 41 41 41 41 41 41 41 41 41 41 41 00 00 21  |AAAAAAAAAAAAA..!|
+ * 00030: 00 01                                            |..              |
+ * Jul 7 19:17:47.087 - SmbFile exception
+ * java.net.UnknownHostException: no name with type 0x20 with no scope for host 140.240.194.37
+ *     at jcifs.netbios.NbtAddress.getAllByAddress(NbtAddress.java:618)
+ *     at jcifs.smb.SmbFile.list(SmbFile.java:700)
+ *     at List.main(List.java:30)
+ * </pre></blockquote>
+ * 
+ * To use this logging facility simply add any
+ * <code>Log.println</code>, <code>Log.printHexDump</code>,
+ * <code>Log.printStackTrace</code>, or derived methods throughout
+ * your code and set a suitable mask with <code>Log.setMask</code>. For
+ * example the following mask might be set at the very beginning of your
+ * program:
+ * 
+ * <p><blockquote><pre>
+ * Log.setMask(( Log.EXCEPTIONS | foo.Log.ALL ) & ~foo.Log.LOGINS );
+ * </pre></blockquote>
+ *
+ * This would write the stack traces from <code>Log.printStackTrace</code>
+ * calls and all logging for package <code>foo</code> with the exception
+ * of logging associated with the <code>LOGINS</code> mask. The following
+ * is an example of using the <code>Log.println</code> method:
+ *
+ * <p><blockquote><pre>
+ * Log.println( Log.WARNINGS, "smb tree connect warning", " path=" + path );
+ * </pre></blockquote>
+ *
+ * <p>Masks can be combined and subtracted with one another using
+ * bitwise operators. To combine two masks use the bitwise OR operator
+ * <code>|</code>. The bitwise AND operator <code>&amp;</code> together with
+ * bitwise NOT <code>~</code> can be used to turn off masks.
+ *
+ * <p>If bit manipulation is not familiar, use the <code>addMask</code>
+ * and <code>subtractMask</code> methods. The equivalent of the first code
+ * sample would be:
+ *
+ * <p><blockquote><pre>
+ * Log.addMask( Log.EXCEPTIONS );
+ * Log.addMask( foo.Log.ALL );
+ * Log.subtractMask( foo.Log.LOGINS );
+ * </pre></blockquote>
+ *
+ * <p>Note: When defining a new mask, one must take care not to use bits
+ * that are already being used by another package. In the future, masks
+ * may be statically assigned during class initialization.
+ *
+ * @see       jcifs.util.LogWriter
+ * @see       jcifs.netbios.Log
+ * @see       jcifs.smb.Log
+ * @since     jcifs-0.1
+ */
+
+public class Log {
+
+    // supress javadoc constructor summary by removing 'protected'
+    protected Log() {}
+
+    private static final char[] hexChars = { 
+        '0', '1', '2', '3', '4', '5',
+        '6', '7', '8', '9', 'A', 'B',
+        'C', 'D', 'E', 'F'
+    };
+    private static final char[] spaceChars = {
+        ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+        ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+        ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
+    };
+
+/**
+ * The systems line separator.
+ */
+
+    public static final String NL = System.getProperty( "line.separator" );
+
+/**
+ * The systems line separator length.
+ */
+
+    public static final int NL_LENGTH = NL.length();
+
+/**
+ * Mask to indicate that no messages should be logged(not even exceptions).
+ */
+
+    public static final int NONE        = 0x00000000;
+
+/**
+ * Log all messages.
+ */
+
+    public static final int ALL            = 0xFFFFFFFF;
+
+/** 
+ * This is the default mask. However, be aware that specifying a
+ * mask without adding this mask will result in exceptions not being
+ * logged. One should always add this EXCEPTIONS mask to the {@link
+ * jcifs.util.Log#setMask(int mask)} expression unless you are explicitly
+ * trying to suppress them. Of course only exceptions that go through
+ * the {@link jcifs.util.Log#printStackTrace(String desc, Throwable t )}
+ * facility can be filtered out.
+ */
+
+    public static final int EXCEPTIONS    = 0x10000001;
+
+/**
+ * Log only critical exceptions. All exceptions logged with
+ * <code>printStackTrace</code> are considered critical. Exceptions are not
+ * critical if they are logged with the <code>NON_CRITICAL_EXCEPTIONS</code>
+ * mask.
+ */
+
+       public static final int CRITICAL_EXCEPTIONS = 0x00000001;
+
+/**
+ * Log non-critical exceptions. The <code>EXCEPTIONS</code> mask consists of both critical and non-critical exceptions.
+ */
+
+       public static final int NON_CRITICAL_EXCEPTIONS = 0x10000000;
+
+/**
+ * Log warning messages.
+ */
+
+    public static final int WARNINGS    = 0x00000002;
+
+/** 
+ * Use this mask while actively debugging your code. It is
+ * an alternative for the popular <code>System.out.println( "MADE
+ * IT!" )</code> statement but can be supressed.
+ */
+
+    public static final int DEBUGGING    = 0x00000004;
+
+/** 
+ * This controls wheather or not {@link jcifs.util.Log#printHexDump}
+ * messages are logged.
+ */ 
+
+    public static final int HEX_DUMPS    = 0x00000008;
+
+/** 
+ * The shared output stream of all <code>Log</code> classes. The
+ * defualt is <code>System.out</code>.
+ */
+
+    protected static LogWriter out = new LogWriter( System.out );
+
+/** 
+ * This is the integer mask that controls what is logged. It is shared
+ * by all Log classes. The default mask is <code>EXCEPTIONS</code>
+ * which consists of <code>CRITICAL_EXCEPTIONS</code> and
+ * <code>NON_CRITICAL_EXCEPTIONS</code>.
+ */ 
+
+    protected static int mask = EXCEPTIONS;
+
+    // Setting Methods
+
+/** 
+ * Specify an {@link java.io.OutputStream} to be used as the underlying
+ * stream.
+ * 
+ * @param out the output stream
+ */
+
+    public static void setPrintWriter( OutputStream out ) {
+        Log.out = new LogWriter( out );
+    }
+
+/** 
+ * This controls what is passed to {@link java.text.SimpleDateFormat} to
+ * control what the timestamp looks like in the log stream. For example, a
+ * format of <code>"EEE, MMM d, h:mm:ss a"</code> would generate timestamps
+ * that read <code>Tue, Mar 14, 4:57:02 PM</code>. This is a whistle.
+ *
+ * @param the format string
+ * @see   java.util.SimpleDateFormat
+ */ 
+
+    public static void setDateFormat( String format ) {
+        out.setDateFormat( format );
+    }
+
+/** 
+ * Set the mask used to screen all calls to logging methods. The idea
+ * here is that the mask can be specified as an arithmetic expression
+ * to perovide a crude but effective syslog style way to dictate what it
+ * logged. For example:
+ * <p><blockquote><pre>
+ *  setMask( Log.EXCEPTIONS +
+ *           Log.HEX_DUMPS +
+ *           jcifs.netbios.Log.PACKET_DATA );
+ *
+ *  setMask( Log.ALL - jcifs.netbios.Log.PACKET_DIAGRAMS );
+ * </pre></blockquote>
+ */ 
+
+    public static void setMask( int mask ) {
+        Log.mask = mask;
+    }
+       public static boolean isSet( int mask ) {
+               return ( Log.mask & mask ) == mask;
+       }
+       public static void addMask( int mask ) {
+               Log.mask |= mask;
+       }
+       public static void subtractMask( int mask ) {
+               Log.mask &= ~mask;
+       }
+
+/** 
+ * Provides standard way to log any {@link java.lang.Throwable} object like
+ * an {@link java.lang.Exception}.
+ */
+       public static void printStackTrace( String desc, Throwable t ) {
+        if(( CRITICAL_EXCEPTIONS & mask ) != 0 )
+            out.printStackTrace( desc, t );
+    }
+       public static void printStackTrace( int type, String desc, Throwable t ) {
+        if(( type & mask ) != 0 )
+            out.printStackTrace( desc, t );
+    }
+
+    // Output Methods Used Only By This Package
+/** 
+ * Hex dumps are ubiquitous enough to provide a standard and easy-to-use
+ * method for logging them. All that is required to use this is setting
+ * the mask for {@link jcifs.util.Log#HEX_DUMPS}. The hex dump output is
+ * represended in the standard form and is quite efficient. Many mega bytes
+ * of source data could be dumped to a file without worry.
+ * 
+ * <p><blockquote><pre>
+ * 00000: 04 d2 29 00 00 01 00 00 00 00 00 01 20 45 47 46  |..)......... EGF|
+ * 00010: 43 45 46 45 45 43 41 43 41 43 41 43 41 43 41 43  |CEFEECACACACACAC|
+ * 00020: 41 43 41 43 41 43 41 43 41 43 41 41 44 00 00 20  |ACACACACACAAD.. |
+ * 00030: 00 01 c0 0c 00 20 00 01 00 00 00 00 00 06 20 00  |..... ........ .|
+ * 00040: ac 22 22 e1                                      |."".            |
+ * </blockquote></pre>
+ */
+
+       public static void printHexDump( String desc, byte[] src ) {
+               printHexDump( desc, src, 0, src.length );
+       }
+    public static void printHexDump( String desc, byte[] src, int srcIndex, int length ) {
+        if(( HEX_DUMPS & mask ) == 0 || length == 0 ) {
+            return;
+        }
+        int s = length % 16;
+        int r = ( s == 0 ) ? length / 16 : length / 16 + 1;
+        char[] c = new char[r * (74 + NL_LENGTH)];
+        char[] d = new char[16];
+        int i;
+        int si = 0;
+        int ci = 0;
+        do {
+            toHexChars( si, c, ci, 5 );
+            ci += 5;
+            c[ci++] = ':';
+            do {
+                if( si == length ) {
+                    int n = 16 - s;
+                    System.arraycopy( spaceChars, 0, c, ci, n * 3 );
+                    ci += n * 3;
+                    System.arraycopy( spaceChars, 0, d, s, n );
+                    break;
+                }
+                c[ci++] = ' ';
+                i = src[srcIndex + si] & 0xFF;
+                toHexChars( i, c, ci, 2 );
+                ci += 2; 
+                if( i < 0 || Character.isISOControl( (char)i )) {
+                    d[si % 16] = '.';
+                } else {
+                    d[si % 16] = (char)i;
+                }
+            } while(( ++si % 16 ) != 0 );
+            c[ci++] = ' ';
+            c[ci++] = ' ';
+            c[ci++] = '|';
+            System.arraycopy( d, 0, c, ci, 16 );
+            ci += 16;
+            c[ci++] = '|';
+            NL.getChars( 0, NL_LENGTH, c, ci );
+            ci += NL_LENGTH;
+        } while( si < length );
+        out.println( desc, c );
+    }
+
+/** 
+ * This is an alternative to the <code>java.lang.Integer.toHexString</cod>
+ * method. It is an efficient relative that also will pad the left side so
+ * that the result is <code>size</code> digits.
+ */ 
+
+    public static String getHexString( int val, int size ) {
+        char[] c = new char[size];
+        toHexChars( val, c, 0, size );
+        return new String( c );
+    }
+    public static String getHexString( long val, int size ) {
+        char[] c = new char[size];
+        toHexChars( val, c, 0, size );
+        return new String( c );
+    }
+
+       public static String getHexString( byte[] src, int srcIndex, int size ) {
+               char[] c = new char[size];
+               size = ( size % 2 == 0 ) ? size / 2 : size / 2 + 1;
+               for( int i = 0, j = 0; i < size; i++ ) {
+                       c[j++] = hexChars[(src[i] >> 4 ) & 0x0F];
+                       if( j == c.length ) {
+                               break;
+                       }
+                       c[j++] = hexChars[src[i] & 0x0F];
+               }
+               return new String( c );
+       }
+
+/** 
+ * This is the same as {@link jcifs.util.Log#getHexString(int val, int
+ * size)} but provides a more practical form when trying to avoid {@link
+ * java.lang.String} concatenation and {@link java.lang.StringBuffer}.
+ */ 
+
+    public static void toHexChars( int val, char dst[], int dstIndex, int size ) {
+        while( size > 0 ) {
+            dst[dstIndex + size - 1] = hexChars[val & 0x000F];
+            if( val != 0 ) {
+                val >>>= 4;
+            }
+            size--;
+        }
+    }
+    public static void toHexChars( long val, char dst[], int dstIndex, int size ) {
+        while( size > 0 ) {
+            dst[dstIndex + size - 1] = hexChars[(int)( val & 0x000FL )];
+            if( val != 0 ) {
+                val >>>= 4;
+            }
+            size--;
+        }
+    }
+
+/** 
+ * Print an int. The bits of the integer <code>type</code> must match the
+ * {@link jcifs.util.Log#mask}.
+ */
+
+    public static void println( int type, String desc, int x ) {
+        if(( type & mask ) != 0 )
+            out.println( desc, x );
+    }
+
+/** 
+ * Print a char[] array. The bits of the integer <code>type</code> must
+ * match the {@link jcifs.util.Log#mask}.
+ */
+    public static void println( int type, String desc, char x[] ) {
+        if(( type & mask ) != 0 )
+            out.println( desc, x );
+    }
+
+/** 
+ * Print a {@link java.lang.String}. The bits of the integer
+ * <code>type</code> must match the {@link jcifs.util.Log#mask}.
+ */
+    public static void println( int type, String desc, String x ) {
+        if(( type & mask ) != 0 )
+            out.println( desc, x );
+    }
+
+/** 
+ * Print an {@link java.lang.Object}. The bits of the integer
+ * <code>type</code> must match the {@link jcifs.util.Log#mask}.
+ */
+    public static void println( int type, String desc, Object x ) {
+        if(( type & mask ) != 0 )
+            out.println( desc, x );
+    }
+
+/**
+ * Print the contents of a {@link java.util.Properties} object to the
+ * log stream using the <code>store</code> method.
+ */
+
+       public static void printProperties( int type, String desc, Properties p ) {
+        if(( type & mask ) != 0 )
+            out.printProperties( desc, p );
+       }
+}
+
diff --git a/src/jcifs/util/LogWriter.java b/src/jcifs/util/LogWriter.java
new file mode 100644 (file)
index 0000000..b495c70
--- /dev/null
@@ -0,0 +1,290 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.util;
+
+import java.io.*;
+import java.util.GregorianCalendar;
+import java.util.Date;
+import java.text.SimpleDateFormat;
+import java.util.Properties;
+
+/** 
+ * This class is basically a {@link java.io.PrintWriter} that prepends
+ * a timestamp before each message is written to the underlying
+ * stream. The methods for printing are a pertainent subset from {@link
+ * java.io.PrintWriter}.
+ *
+ * @see jcifs.util.Log
+ */
+public class LogWriter {
+
+    private Writer out;
+       private OutputStream raw;
+    private PrintWriter eout;
+    private boolean trouble = false;
+    private String lineSeparator;
+
+/**
+ * The object used to synchronize operations on this stream
+ */
+
+    public Object lock;
+
+/** 
+ * Create a new <code>LogWriter</code> instance that uses the specified
+ * output stream as it's underlying stream
+ */
+    public LogWriter( OutputStream out ) {
+        this.out = new OutputStreamWriter( out );
+               raw = out;
+               this.lock = this;
+        eout = new PrintWriter( out );
+        lineSeparator = System.getProperty( "line.separator" );
+    }
+
+    static String dateString;
+    static GregorianCalendar cal;
+    static SimpleDateFormat sdf;
+
+    static {
+        cal = new GregorianCalendar();
+        setDateFormat( "MMM d HH:mm:ss.SSS" );
+    }
+
+/** 
+ * Set the date format used to render the timestamp written with each
+ * message.
+ * 
+ * @param format the format string used
+ * @see java.text.SimpleDateFormat
+ */
+    public static void setDateFormat( String format ) {
+        sdf = new SimpleDateFormat( format );
+        sdf.setCalendar( cal );
+    }
+
+    private void ensureOpen() throws IOException {
+        if( out == null )
+            throw new IOException( "Stream closed" );
+    }
+
+/**
+ * Close the stream
+ */
+
+    public void close() {
+        try {
+            synchronized( lock ) {
+                if( out == null )
+                    return;
+                out.close();
+                out = null;
+            }
+        } catch( IOException x ) {
+            trouble = true;
+        }
+    }
+
+/**
+ * Flush the stream and check error state
+ */
+
+    public boolean checkError() {
+        if( out != null ) {
+            try {
+                synchronized( lock ) {
+                    ensureOpen();
+                    out.flush();
+                }
+            } catch( IOException x ) {
+                trouble = true;
+            }
+        }
+        return trouble;
+    }
+
+/** 
+ * Indicate that an error has occured
+ */
+
+    public void setError() {
+        trouble = true;
+    }
+
+/**
+ * This is a pervasive enough feature for a logging utility that it is
+ * built in.
+ *
+ * @param desc a brief description of the source of the message to follow
+ * @param t the <code>Exception</code> to obtain the message to be printed from
+ */
+
+    public void printStackTrace( String desc, Throwable t ) {
+        try {
+            synchronized( lock ) {
+                ensureOpen();
+                out.write( sdf.format( new Date() ));
+                out.write( " - " );
+                out.write( desc );
+                out.write( lineSeparator );
+                               eout.flush();
+                out.flush();
+                t.printStackTrace( eout );
+                               eout.flush();
+                out.flush();
+            }
+        } catch( InterruptedIOException x ) {
+            Thread.currentThread().interrupt();
+        } catch( IOException ioe ) {
+            trouble = true;
+        }
+    }
+
+
+
+/** 
+ * Print an <code>int</code> to the log stream. Keep in mind that every
+ * call to a <code>PrintWriter</code> like method will print a new timestamp.
+ * Using several calls together will not concatonate several messages
+ * together under one timestamp.
+ *
+ * @param desc a brief description of the source of the message to follow
+ * @param i the <code>int</code> to print
+ */
+    public void println( String desc, int i ) {
+        try {
+            synchronized( lock ) {
+                ensureOpen();
+                out.write( sdf.format( new Date() ));
+                out.write( " - " );
+                out.write( desc );
+                out.write( lineSeparator );
+                out.write( Integer.toString( i ));
+                out.write( lineSeparator );
+                out.flush();
+            }
+        } catch( InterruptedIOException x ) {
+            Thread.currentThread().interrupt();
+        } catch( IOException ioe ) {
+            trouble = true;
+        }
+    }
+
+/** 
+ * Print an array of <code>char</code> to the log.
+ * 
+ * @param desc a brief description of the source of the message to follow
+ * @param c the message
+ */
+    public void println( String desc, char c[] ) {
+        try {
+            synchronized( lock ) {
+                ensureOpen();
+                out.write( sdf.format( new Date() ));
+                out.write( " - " );
+                out.write( desc );
+                out.write( lineSeparator );
+                out.write( c );
+                out.write( lineSeparator );
+                out.flush();
+            }
+        } catch( InterruptedIOException x ) {
+            Thread.currentThread().interrupt();
+        } catch( IOException ioe ) {
+            trouble = true;
+        }
+    }
+
+/** 
+ * Print a <code>String</code> to the log.
+ * 
+ * @param desc a brief description of the source of the message to follow
+ * @param s the string message
+ */ 
+
+    public void println( String desc, String s ) {
+        try {
+            synchronized( lock ) {
+                ensureOpen();
+                out.write( sdf.format( new Date() ));
+                out.write( " - " );
+                out.write( desc );
+                out.write( lineSeparator );
+                out.write( s );
+                out.write( lineSeparator );
+                out.flush();
+            }
+        } catch( InterruptedIOException x ) {
+            Thread.currentThread().interrupt();
+        } catch( IOException ioe ) {
+            trouble = true;
+        }
+    }
+
+/** 
+ * Print the string representation of an <code>Object</code> to the screen.
+ *
+ * @param desc a general description of the source of the message
+ * @param o the <code>Object</code> to print
+ */
+    public void println( String desc, Object o ) {
+        try {
+            synchronized( lock ) {
+                ensureOpen();
+                out.write( sdf.format( new Date() ));
+                out.write( " - " );
+                out.write( desc );
+                out.write( lineSeparator );
+                out.write( String.valueOf( o ));
+                out.write( lineSeparator );
+                out.flush();
+            }
+        } catch( InterruptedIOException x ) {
+            Thread.currentThread().interrupt();
+        } catch( IOException ioe ) {
+            trouble = true;
+        }
+    }
+/**
+ * Print the contents of a {@link java.util.Properties} object to the
+ * log stream using the <code>store</code> method.
+ */
+
+       public void printProperties( String desc, Properties p ) {
+        try {
+            synchronized( lock ) {
+                ensureOpen();
+                p.save( raw, desc );
+                out.write( lineSeparator );
+                out.flush();
+            }
+        } catch( InterruptedIOException x ) {
+            Thread.currentThread().interrupt();
+        } catch( IOException ioe ) {
+            trouble = true;
+        }
+    }
+}
+
diff --git a/src/jcifs/util/MD4.java b/src/jcifs/util/MD4.java
new file mode 100644 (file)
index 0000000..ce5889e
--- /dev/null
@@ -0,0 +1,299 @@
+// This file is currently unlocked (change this line if you lock the file)
+//
+// $Log: MD4.java,v $
+// Revision 1.2  1998/01/05 03:41:19  iang
+// Added references only.
+//
+// Revision 1.1.1.1  1997/11/03 22:36:56  hopwood
+// + Imported to CVS (tagged as 'start').
+//
+// Revision 0.1.0.0  1997/07/14  R. Naffah
+// + original version
+//
+// $Endlog$
+/*
+ * Copyright (c) 1997 Systemics Ltd
+ * on behalf of the Cryptix Development Team.  All rights reserved.
+ */
+
+package jcifs.util;
+
+import java.security.MessageDigest;
+
+/**
+ * Implements the MD4 message digest algorithm in Java.
+ * <p>
+ * <b>References:</b>
+ * <ol>
+ *   <li> Ronald L. Rivest,
+ *        "<a href="http://www.roxen.com/rfc/rfc1320.html">
+ *        The MD4 Message-Digest Algorithm</a>",
+ *        IETF RFC-1320 (informational).
+ * </ol>
+ *
+ * <p><b>$Revision: 1.2 $</b>
+ * @author  Raif S. Naffah
+ */
+public  class MD4 extends MessageDigest implements Cloneable
+{
+// MD4 specific object variables
+//...........................................................................
+
+    /**
+     * The size in bytes of the input block to the tranformation algorithm.
+     */
+    private static final int BLOCK_LENGTH = 64;       //    = 512 / 8;
+
+    /**
+     * 4 32-bit words (interim result)
+     */
+    private int[] context = new int[4];
+
+    /**
+     * Number of bytes processed so far mod. 2 power of 64.
+     */
+    private long count;
+
+    /**
+     * 512 bits input buffer = 16 x 32-bit words holds until reaches 512 bits.
+     */
+    private byte[] buffer = new byte[BLOCK_LENGTH];
+
+    /**
+     * 512 bits work buffer = 16 x 32-bit words
+     */
+    private int[] X = new int[16];
+
+
+// Constructors
+//...........................................................................
+
+    public MD4 () {
+        super("MD4");
+        engineReset();
+    }
+
+    /**
+     *    This constructor is here to implement cloneability of this class.
+     */
+    private MD4 (MD4 md) {
+        this();
+        context = (int[])md.context.clone();
+        buffer = (byte[])md.buffer.clone();
+        count = md.count;
+    }
+
+
+// Cloneable method implementation
+//...........................................................................
+
+    /**
+     * Returns a copy of this MD object.
+     */
+    public Object clone() { return new MD4(this); }
+
+
+// JCE methods
+//...........................................................................
+
+    /**
+     * Resets this object disregarding any temporary data present at the
+     * time of the invocation of this call.
+     */
+    public void engineReset () {
+        // initial values of MD4 i.e. A, B, C, D
+        // as per rfc-1320; they are low-order byte first
+        context[0] = 0x67452301;
+        context[1] = 0xEFCDAB89;
+        context[2] = 0x98BADCFE;
+        context[3] = 0x10325476;
+        count = 0L;
+        for (int i = 0; i < BLOCK_LENGTH; i++)
+            buffer[i] = 0;
+    }
+
+    /**
+     * Continues an MD4 message digest using the input byte.
+     */
+    public void engineUpdate (byte b) {
+        // compute number of bytes still unhashed; ie. present in buffer
+        int i = (int)(count % BLOCK_LENGTH);
+        count++;                                        // update number of bytes
+        buffer[i] = b;
+        if (i == BLOCK_LENGTH - 1)
+            transform(buffer, 0);
+    }
+
+    /**
+     * MD4 block update operation.
+     * <p>
+     * Continues an MD4 message digest operation, by filling the buffer,
+     * transform(ing) data in 512-bit message block(s), updating the variables
+     * context and count, and leaving (buffering) the remaining bytes in buffer
+     * for the next update or finish.
+     *
+     * @param    input    input block
+     * @param    offset    start of meaningful bytes in input
+     * @param    len        count of bytes in input block to consider
+     */
+    public void engineUpdate (byte[] input, int offset, int len) {
+        // make sure we don't exceed input's allocated size/length
+        if (offset < 0 || len < 0 || (long)offset + len > input.length)
+            throw new ArrayIndexOutOfBoundsException();
+
+        // compute number of bytes still unhashed; ie. present in buffer
+        int bufferNdx = (int)(count % BLOCK_LENGTH);
+        count += len;                                        // update number of bytes
+        int partLen = BLOCK_LENGTH - bufferNdx;
+        int i = 0;
+        if (len >= partLen) {
+            System.arraycopy(input, offset, buffer, bufferNdx, partLen);
+
+
+            transform(buffer, 0);
+
+            for (i = partLen; i + BLOCK_LENGTH - 1 < len; i+= BLOCK_LENGTH)
+                transform(input, offset + i);
+            bufferNdx = 0;
+        }
+        // buffer remaining input
+        if (i < len)
+            System.arraycopy(input, offset + i, buffer, bufferNdx, len - i);
+    }
+
+    /**
+     * Completes the hash computation by performing final operations such
+     * as padding. At the return of this engineDigest, the MD engine is
+     * reset.
+     *
+     * @return the array of bytes for the resulting hash value.
+     */
+    public byte[] engineDigest () {
+        // pad output to 56 mod 64; as RFC1320 puts it: congruent to 448 mod 512
+        int bufferNdx = (int)(count % BLOCK_LENGTH);
+        int padLen = (bufferNdx < 56) ? (56 - bufferNdx) : (120 - bufferNdx);
+
+        // padding is alwas binary 1 followed by binary 0s
+        byte[] tail = new byte[padLen + 8];
+        tail[0] = (byte)0x80;
+
+        // append length before final transform:
+        // save number of bits, casting the long to an array of 8 bytes
+        // save low-order byte first.
+        for (int i = 0; i < 8; i++)
+            tail[padLen + i] = (byte)((count * 8) >>> (8 * i));
+
+        engineUpdate(tail, 0, tail.length);
+
+        byte[] result = new byte[16];
+        // cast this MD4's context (array of 4 ints) into an array of 16 bytes.
+        for (int i = 0; i < 4; i++)
+            for (int j = 0; j < 4; j++)
+                result[i * 4 + j] = (byte)(context[i] >>> (8 * j));
+
+        // reset the engine
+        engineReset();
+        return result;
+    }
+
+
+// own methods
+//...........................................................................
+
+    /**
+     *    MD4 basic transformation.
+     *    <p>
+     *    Transforms context based on 512 bits from input block starting
+     *    from the offset'th byte.
+     *
+     *    @param    block    input sub-array.
+     *    @param    offset    starting position of sub-array.
+     */
+    private void transform (byte[] block, int offset) {
+
+        // encodes 64 bytes from input block into an array of 16 32-bit
+        // entities. Use A as a temp var.
+        for (int i = 0; i < 16; i++)
+            X[i] = (block[offset++] & 0xFF)       |
+                   (block[offset++] & 0xFF) <<  8 |
+                   (block[offset++] & 0xFF) << 16 |
+                   (block[offset++] & 0xFF) << 24;
+
+
+        int A = context[0];
+        int B = context[1];
+        int C = context[2];
+        int D = context[3];
+
+        A = FF(A, B, C, D, X[ 0],  3);
+        D = FF(D, A, B, C, X[ 1],  7);
+        C = FF(C, D, A, B, X[ 2], 11);
+        B = FF(B, C, D, A, X[ 3], 19);
+        A = FF(A, B, C, D, X[ 4],  3);
+        D = FF(D, A, B, C, X[ 5],  7);
+        C = FF(C, D, A, B, X[ 6], 11);
+        B = FF(B, C, D, A, X[ 7], 19);
+        A = FF(A, B, C, D, X[ 8],  3);
+        D = FF(D, A, B, C, X[ 9],  7);
+        C = FF(C, D, A, B, X[10], 11);
+        B = FF(B, C, D, A, X[11], 19);
+        A = FF(A, B, C, D, X[12],  3);
+        D = FF(D, A, B, C, X[13],  7);
+        C = FF(C, D, A, B, X[14], 11);
+        B = FF(B, C, D, A, X[15], 19);
+
+        A = GG(A, B, C, D, X[ 0],  3);
+        D = GG(D, A, B, C, X[ 4],  5);
+        C = GG(C, D, A, B, X[ 8],  9);
+        B = GG(B, C, D, A, X[12], 13);
+        A = GG(A, B, C, D, X[ 1],  3);
+        D = GG(D, A, B, C, X[ 5],  5);
+        C = GG(C, D, A, B, X[ 9],  9);
+        B = GG(B, C, D, A, X[13], 13);
+        A = GG(A, B, C, D, X[ 2],  3);
+        D = GG(D, A, B, C, X[ 6],  5);
+        C = GG(C, D, A, B, X[10],  9);
+        B = GG(B, C, D, A, X[14], 13);
+        A = GG(A, B, C, D, X[ 3],  3);
+        D = GG(D, A, B, C, X[ 7],  5);
+        C = GG(C, D, A, B, X[11],  9);
+        B = GG(B, C, D, A, X[15], 13);
+
+        A = HH(A, B, C, D, X[ 0],  3);
+        D = HH(D, A, B, C, X[ 8],  9);
+        C = HH(C, D, A, B, X[ 4], 11);
+        B = HH(B, C, D, A, X[12], 15);
+        A = HH(A, B, C, D, X[ 2],  3);
+        D = HH(D, A, B, C, X[10],  9);
+        C = HH(C, D, A, B, X[ 6], 11);
+        B = HH(B, C, D, A, X[14], 15);
+        A = HH(A, B, C, D, X[ 1],  3);
+        D = HH(D, A, B, C, X[ 9],  9);
+        C = HH(C, D, A, B, X[ 5], 11);
+        B = HH(B, C, D, A, X[13], 15);
+        A = HH(A, B, C, D, X[ 3],  3);
+        D = HH(D, A, B, C, X[11],  9);
+        C = HH(C, D, A, B, X[ 7], 11);
+        B = HH(B, C, D, A, X[15], 15);
+
+        context[0] += A;
+        context[1] += B;
+        context[2] += C;
+        context[3] += D;
+    }
+
+    // The basic MD4 atomic functions.
+
+    private int FF (int a, int b, int c, int d, int x, int s) {
+        int t = a + ((b & c) | (~b & d)) + x;
+        return t << s | t >>> (32 - s);
+    }
+    private int GG (int a, int b, int c, int d, int x, int s) {
+        int t = a + ((b & (c | d)) | (c & d)) + x + 0x5A827999;
+        return t << s | t >>> (32 - s);
+    }
+    private int HH (int a, int b, int c, int d, int x, int s) {
+        int t = a + (b ^ c ^ d) + x + 0x6ED9EBA1;
+        return t << s | t >>> (32 - s);
+    }
+}
diff --git a/src/jcifs/util/PropertiesTree.java b/src/jcifs/util/PropertiesTree.java
new file mode 100644 (file)
index 0000000..481efb0
--- /dev/null
@@ -0,0 +1,573 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2000  "Michael B. Allen" <mballen@erols.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+package jcifs.util;
+
+import java.util.Properties;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.IOException;
+import java.util.Date;
+
+/**
+ *
+ * 
+ * This class is backwords compatible with {@link java.util.Properties}
+ * however another dimension is added by using the customary dot '.' as
+ * an operator to alternativly represent properties as trees. In essance
+ * it gives meaning to the '.' used in keys of properties whereas with
+ * traditional properties usage of the dot '.' was mearly a convention. This
+ * allows applications to organize there data in new ways. The following
+ * is an example of the "tagged" output from a PropertiesTree along with
+ * traditional output from the same PropertiesTree to
+ * it's right. PropertiesTree can load and store
+ * both formats at runtime(e.g. load traditional and then store tagged).
+ * 
+ * <p><table border="1" cellpadding="3" cellspacing="0" width="100%"><tr><td>
+ * <pre>
+ * #Feed Processor Config
+ * #Sun Dec 31 00:48:23 EST 2000
+ *
+ * proxy=192.168.1.15
+ * &lt;net&gt;
+ *     username=joe
+ *     &lt;smb&gt;
+ *         host=doc-storage
+ *         username=kelly
+ *     &lt;/smb&gt;
+ *     &lt;ftp&gt;
+ *         host=feed10.research.com
+ *     &lt;/ftp&gt;
+ * &lt;/net&gt;
+ * </pre>
+ * 
+ * </td><td>
+ * 
+ * <pre>
+ * #Feed Processor Config
+ * #Sun Dec 31 00:59:31 EST 2000
+ *
+ * proxy=192.168.1.15
+ * net.username=joe
+ * net.smb.host=doc-storage
+ * net.smb.username=kelly
+ * net.ftp.host=feed10.research.com
+ * </pre>
+ * 
+ * </td></tr></table>
+ *
+ * <p>In the above example, if <code>getProperty( "net.ftp.username" )</code>
+ * was called "joe" would be returned. The <code>get</code> method walks
+ * up the tree searching for the first match. So the following:
+ * 
+ * <pre>
+ *     net.ftp.username
+ *     net.username
+ *     username
+ * </pre>
+ * 
+ * are basically equivalent and thus backwords compatible with
+ * java.util.Properties.
+ *
+ * <p>The benifit of using <code>PropertiesTree</code> as opposed to <code>Properties</code> is that a child property can mask a parent
+ * property resulting in sophisticated hierarchial relationships. This is true of the <code>net.smb.username</code> property.
+ * It might also be thought of as overloading <code>net.username</code>
+ * with <code>net.smb.username</code> but only for the smb branch.
+ *
+ * <p>See the <a href="../../../properties.html">More About PropertiesTree and it's File Format</a> for details.
+ */
+
+public class PropertiesTree extends Properties {
+
+       private static final String INDENT = "    ";
+       private static final int TRUNC = 70;
+
+       String label;
+       private PropertiesTree parent;
+
+       private void listTagged( String indent, PrintStream out ) {
+               Vector sections = new Vector(0);
+               for( Enumeration e = keys(); e.hasMoreElements(); ) {
+                       String key = (String)e.nextElement();
+                       Object value = get( key );
+                       if( value instanceof PropertiesTree ) {
+                               sections.addElement( value );
+                       } else {
+                               String s;
+                               s = indent + key + "=" + (String)value;
+                               s = s.length() > TRUNC ? s.substring( 0, TRUNC - 3 ) + "..." : s;
+                               out.println( s );
+                       }
+               }
+               for( Enumeration e1 = sections.elements(); e1.hasMoreElements(); ) {
+                       String s;
+                       PropertiesTree p = (PropertiesTree)e1.nextElement();
+
+                       s = indent + "<" + p.label + ">";
+                       s = s.length() > TRUNC ? s.substring( 0, TRUNC - 3 ) + "..." : s;
+                       out.println( s );
+
+                       p.list0( indent + INDENT, out );
+
+                       s = indent + "</" + p.label + ">";
+                       s = s.length() > TRUNC ? s.substring( 0, TRUNC - 3 ) + "..." : s;
+                       out.println( s );
+               }
+       }
+       private void list0( String prefix, PrintStream out ) {
+               Vector sections = new Vector(0);
+               for( Enumeration e = keys(); e.hasMoreElements(); ) {
+                       String key = (String)e.nextElement();
+                       Object value = get( key );
+                       if( value == null ) {
+                       } else if( value instanceof PropertiesTree ) {
+                               sections.addElement( value );
+                       } else {
+                               if( prefix != null ) {
+                                       key = prefix + "." + key;
+                               }
+                               String s = (String)value;
+                               s = s.length() > TRUNC ? s.substring( 0, TRUNC - 3 ) + "..." : s;
+                               out.println( key + "=" + s );
+                       }
+               }
+               for( Enumeration e1 = sections.elements(); e1.hasMoreElements(); ) {
+                       PropertiesTree p = (PropertiesTree)e1.nextElement();
+                       p.list0( prefix == null ? p.label : prefix + "." + p.label, out );
+               }
+       }
+       private synchronized void saveTagged( String indent, PrintWriter out ) {
+               Vector sections = new Vector(0);
+               for( Enumeration e = keys(); e.hasMoreElements(); ) {
+                       String key = (String)e.nextElement();
+                       Object value = get( key );
+                       if( value == null ) {
+                               value = "";
+                       }
+                       if( value instanceof PropertiesTree ) {
+                               sections.addElement( value );
+                       } else if( value instanceof String ) {
+                               out.print( indent );
+                               out.print( key );
+                               out.write( '=' );
+
+                               String val = (String)value;
+                               int len = val.length();
+                               boolean empty = false;
+
+                               for (int i = 0 ; i < len ; i++) {
+                                       int ch = val.charAt(i);
+
+                                       switch (ch) {
+                                               case '\\': out.write('\\'); out.write('\\'); break;
+                                               case '\t': out.write('\\'); out.write('t'); break;
+                                               case '\n': out.write('\\'); out.write('n'); break;
+                                               case '\r': out.write('\\'); out.write('r'); break;
+
+                                               default:
+                                                       if ((ch < ' ') || (ch >= 127) || (empty && (ch == ' '))) {
+                                                               if( ch > 255 ) {
+                                                                       out.write(ch);
+                                                               } else {
+                                                                       out.write('\\');
+                                                                       out.write('u');
+                                                                       out.write(toHex((ch >> 12) & 0xF));
+                                                                       out.write(toHex((ch >>  8) & 0xF));
+                                                                       out.write(toHex((ch >>  4) & 0xF));
+                                                                       out.write(toHex((ch >>  0) & 0xF));
+                                                               }
+                                                       } else {
+                                                               out.write(ch);
+                                                       }
+                                       }
+                                       empty = false;
+                               }
+                               out.write('\n');
+                               out.flush();
+                       } else {
+                               System.out.println( "error: " + key + "=" + value );
+                       }
+               }
+               for( Enumeration e1 = sections.elements(); e1.hasMoreElements(); ) {
+                       PropertiesTree p = (PropertiesTree)e1.nextElement();
+                       out.println( indent + "<" + p.label + ">" );
+                       p.saveTagged( indent + INDENT, out );
+                       out.println( indent + "</" + p.label + ">" );
+               }
+       }
+       private synchronized void save0( String prefix, PrintWriter out ) {
+               Vector sections = new Vector(0);
+               for( Enumeration e = keys(); e.hasMoreElements(); ) {
+                       String key = (String)e.nextElement();
+                       Object value = get( key );
+                       if( value == null ) {
+                               value = "";
+                       }
+                       if( value instanceof PropertiesTree ) {
+                               sections.addElement( value );
+                       } else if( value instanceof String ) {
+                               if( prefix != null ) {
+                                       out.print( prefix );
+                                       out.write( '.' );
+                               }
+                               out.print( key );
+                               out.write( '=' );
+
+                               String val = (String)value;
+                               int len = val.length();
+                               boolean empty = false;
+
+                               for (int i = 0 ; i < len ; i++) {
+                                       int ch = val.charAt(i);
+
+                                       switch (ch) {
+                                               case '\\': out.write('\\'); out.write('\\'); break;
+                                               case '\t': out.write('\\'); out.write('t'); break;
+                                               case '\n': out.write('\\'); out.write('n'); break;
+                                               case '\r': out.write('\\'); out.write('r'); break;
+
+                                               default:
+                                                       if ((ch < ' ') || (ch >= 127) || (empty && (ch == ' '))) {
+                                                               if( ch > 255 ) {
+                                                                       out.write(ch);
+                                                               } else {
+                                                                       out.write('\\');
+                                                                       out.write('u');
+                                                                       out.write(toHex((ch >> 12) & 0xF));
+                                                                       out.write(toHex((ch >>  8) & 0xF));
+                                                                       out.write(toHex((ch >>  4) & 0xF));
+                                                                       out.write(toHex((ch >>  0) & 0xF));
+                                                               }
+                                                       } else {
+                                                               out.write(ch);
+                                                       }
+                                       }
+                                       empty = false;
+                               }
+                               out.write('\n');
+                               out.flush();
+                       } else {
+                               System.out.println( "error: " + key + "=" + value );
+                       }
+               }
+               for( Enumeration e1 = sections.elements(); e1.hasMoreElements(); ) {
+                       PropertiesTree p = (PropertiesTree)e1.nextElement();
+                       p.save0( prefix == null ? p.label : prefix + "." + p.label, out );
+               }
+       }
+       private static char toHex(int nibble) {
+               return hexDigit[(nibble & 0xF)];
+       }
+       private static char[] hexDigit = {
+               '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
+       };
+
+       /**
+        * Construct an empty properties tree with no values.
+        */
+
+       public PropertiesTree() {
+               this.label = null;
+               this.parent = null;
+       }
+
+       /** 
+        * Put a key and value into the tree. If the key contains a dot
+        * '.', new tree nodes will be automatically created to accomodate.
+        */ 
+
+       public synchronized Object put( Object key, Object value ) {
+               String s = (String)key;
+               String l;
+               Object o;
+               PropertiesTree p;
+               int d;
+               if(( d = s.indexOf( '.' )) > -1 ) {
+                       l = s.substring( 0, d );
+                       o = super.get( l );
+                       if( o != null && o instanceof PropertiesTree ) {
+                               p = (PropertiesTree)o;
+                       } else if( o != null ) {
+                               throw new IllegalArgumentException( "property exists: " +
+                                                                                       l + "=" + (String)o );
+                       } else {
+                               p = new PropertiesTree();
+                               p.label = l;
+                               p.parent = this;
+                               super.put( l, p );
+                       }
+                       return p.put( s.substring( d + 1 ), value );
+               } else {
+                       o = super.get( s );
+                       if( o != null && o instanceof PropertiesTree ) {
+                               throw new IllegalArgumentException( "property tree exists: " + s );
+                       }
+                       if( value instanceof PropertiesTree ) {
+                               ((PropertiesTree)value).label = (String)key;
+                               ((PropertiesTree)value).parent = this;
+                       }
+                       return super.put( key, value );
+               }
+       }
+
+       /** 
+        * Retrieved the property specified by the key parameter, seraching parent
+        * nodes if necessary.
+        */ 
+
+       public synchronized Object get( Object key ) {
+               String s = (String)key;
+               int d;
+               if(( d = s.indexOf( '.' )) > 0 ) {
+                       Object o = super.get( s.substring( 0, d ));
+                       if( o == null ) {
+                               return get( s.substring( d + 1 ));
+                       } else if( o instanceof PropertiesTree ) {
+                               return ((PropertiesTree)o).get( s.substring( d + 1 ));
+                       }
+               } else {
+                       Object o = super.get( s );
+                       if( o == null && parent != null ) {
+                               return parent.get( s );
+                       } else if( o instanceof PropertiesTree ||
+                                       (  o instanceof String && ((String)o).length() > 0 )) {
+                               return o;
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * Retrieve a property from the tree by searching parent nodes
+        * if necessary and return the value as a String.
+        */
+
+       public String getProperty( String key ) {
+               Object o = get( key );
+               return o == null ? null : (String)o;
+       }
+
+       /** 
+        * Retrieve a property from the tree by searching parent nodes if necessary
+        * and return the value as a String. If the keys value is not found, the
+        * default parameter will be returned.
+        */ 
+
+       public String getProperty( String key, String defaultValue ) {
+               Object o = get( key );
+               return o == null ? defaultValue : (String)o;
+       }
+
+       /** 
+        * List all properties in the traditional output format and truncated to
+        * ensure the contents fit within the display.
+        */ 
+
+       public void list( PrintStream out ) {
+               out.println("-- listing properties tree --");
+               list0( null, out );
+       }
+
+       /** 
+        * Save this properties tree to the specified OutputStream. The header
+        * parameter will be printed at the top as a comment.
+        */ 
+
+       public synchronized void store( OutputStream out, String header ) {
+               store( out, header, false );
+       }
+
+       /** 
+        * Write this properties tree to the specified OutputStream. The header
+        * parameter will be printed at the top as a comment. If the boolean
+        * parameter is true the output will be stored in tagged format as shown
+        * in the example at the top of this page.
+        */ 
+
+       public synchronized void store( OutputStream out, String header, boolean tagged ) {
+               PrintWriter prnt = new PrintWriter( out, true );
+               if( header != null ) {
+                       prnt.write( '#' );
+                       prnt.println( header );
+               }
+               prnt.write( '#' );
+               prnt.println( new Date() );
+               if( tagged ) {
+                       saveTagged( "", prnt );
+               } else {
+                       save0( null, prnt );
+               }
+       }
+
+       /** 
+        * Load all properties from the provided InputStream. The text read may be
+        * either tagged format, traditional format, or a mixture of both.
+        */ 
+
+       public synchronized void load( InputStream in ) throws IOException {
+               int buflen = 80;
+               char[] buf = new char[buflen];
+               int bufindx = 0;
+               boolean intag = false;
+               String section = null;
+
+               int ch = in.read();
+               while( true ) {
+                       switch( ch ) {
+                               case -1:
+                                       if( section != null ) {
+                                               throw new IOException( "expecting end tag" );
+                                       }
+                                       return;
+                               case '<':
+                                       intag = true;
+                                       ch = in.read();
+                                       continue;
+                               case '#':
+                               case ';':
+                                       do {
+                                               ch = in.read();
+                                       } while(( ch >= 0 ) && ( ch != '\n' ) && ( ch != '\r' ));
+                                       continue;
+
+                               case '\n':
+                               case '\r':
+                               case ' ':
+                               case '\t':
+                                       ch = in.read();
+                                       continue;
+                       }
+
+                       bufindx = 0;
+                       while(( ch >= 0 ) && ( ch != '=' ) && ( ch != ':' ) && ( ch != ' ' ) &&
+                                                               ( ch != '\t' ) && ( ch != '\n' ) && ( ch != '\r' )) {
+                               if( intag && ch == '>' ) {
+                                       ch = in.read();
+                                       break;
+                               }
+                               if( bufindx >= buflen ) {
+                                       buflen *= 2;
+                                       char[] nbuf = new char[buflen];
+                                       System.arraycopy( buf, 0, nbuf, 0, buf.length );
+                                       buf = nbuf;
+                               }
+                               buf[bufindx++] = (char)ch;
+                               ch = in.read();
+                       }
+                       String key = new String( buf, 0, bufindx );
+                       if( intag ) {
+                               if( key.startsWith( "/" )) {
+                                       int s;
+                                       // chop off end tag from current section
+                                       if( section != null && section.regionMatches(
+                                                       ( s = section.lastIndexOf( '.' )) + 1, key, 1, key.length() - 1 )) {
+                                               section = s < 1 ? null : section.substring( 0, s );
+                                       } else {
+                                               throw new IOException( "unexpected end tag: </" + key + ">" );
+                                       }
+                               } else {
+                                       section = section == null ? key : section + "." + key;
+                               }
+                               intag = false;
+                               continue;
+                       }
+
+                       while(( ch == ' ' ) || ( ch == '\t' )) {
+                               ch = in.read();
+                       }
+                       if(( ch == '=' ) || ( ch == ':' )) {
+                               ch = in.read();
+                       }
+                       while(( ch == ' ' ) || ( ch == '\t' )) {
+                               ch = in.read();
+                       }
+
+                       bufindx = 0;
+                       while(( ch >= 0 ) && ( ch != '\n' ) && ( ch != '\r' )) {
+                               int next = 0;
+                               if( ch == '\\' ) {
+                                       switch( ch = in.read() ) {
+                                               case '\r':
+                                                       if((( ch = in.read() ) == '\n' ) ||
+                                                                       ( ch == ' ' ) || ( ch == '\t' )) {
+                                                       } else continue;
+                                               case '\n': 
+                                                       while((( ch = in.read() ) == ' ') || ( ch == '\t' ));
+                                                       continue;
+                                               case 't': ch = '\t'; next = in.read(); break;
+                                               case 'n': ch = '\n'; next = in.read(); break;
+                                               case 'r': ch = '\r'; next = in.read(); break;
+                                               case 'u': {
+                                                       while ((ch = in.read()) == 'u');
+                                                       int d = 0;
+                                                       loop:
+                                                               for (int i = 0 ; i < 4 ; i++) {
+                                                                       next = in.read();
+                                                                       switch (ch) {
+                                                                               case '0': case '1': case '2': case '3': case '4':
+                                                                               case '5': case '6': case '7': case '8': case '9':
+                                                                                       d = (d << 4) + ch - '0';
+                                                                                       break;
+                                                                               case 'a': case 'b': case 'c':
+                                                                               case 'd': case 'e': case 'f':
+                                                                                       d = (d << 4) + 10 + ch - 'a';
+                                                                                       break;
+                                                                               case 'A': case 'B': case 'C':
+                                                                               case 'D': case 'E': case 'F':
+                                                                                       d = (d << 4) + 10 + ch - 'A';
+                                                                                       break;
+                                                                               default:
+                                                                                       break loop;
+                                                                       }       
+                                                                       ch = next;
+                                                               }
+                                                               ch = d;
+                                                               break;
+                                               }
+                                               default:
+                                                       next = in.read();
+                                                       break;
+                                       }
+                               } else {
+                                       next = in.read();
+                               }
+                               if (bufindx >= buflen) {
+                                       buflen *= 2;
+                                       char[] nbuf = new char[buflen];
+                                       System.arraycopy(buf, 0, nbuf, 0, buf.length);
+                                       buf = nbuf;
+                               }
+                               buf[bufindx++] = (char)ch;
+                               ch = next;
+                       }
+                       String val = new String(buf, 0, bufindx);
+
+                       if( section != null ) {
+                               put( section + '.' + key, val );
+                       } else {
+                               put( key, val );
+                       }
+               }
+       }
+}