/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "Licence").
 * You may not use this file except in compliance with the Licence.
 *
 * You can obtain a copy of the licence at RISC OS path @.^.LICENCE
 * or  http://www.riscosdev.com/lanman98/LICENCE.CDDL
 * See the Licence for the specific language governing permissions
 * and limitations under the Licence.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the Licence file. If applicable, add the
 * following below this CDDL HEADER, with the fields enclosed by
 * brackets "[]" replaced with your own identifying information:
 * Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *   Portions Copyright RISC OS Developments 2019+, credited to the RISC OS One Project.
 */

/*
 *   SMB2, enough of it to reach a server that will no longer speak SMB1.
 *
 *   The transport underneath is the same one SMB1 uses - a four byte
 *   length and then the message - so c.vc carries this unchanged.  Above
 *   that almost nothing is shared: a fixed 64 byte header in place of the
 *   variable one, a message identifier that has to increase, credits that
 *   have to be asked for, names in UTF-16LE throughout, and errors that
 *   are NT status codes with no DOS equivalent on the wire at all.
 */

#ifndef _SMB2_
#define _SMB2_

#include "vc.h"

typedef struct smb2_conn_s *smb2_conn_t;

/* Dialects offered.  3.1.1 is not among them: it needs the negotiate
   contexts and the pre-authentication hash chain, neither of which is here,
   and offering a dialect that cannot then be satisfied is worse than not
   offering it. */
#define SMB2_DIALECT_0202 (0x0202)
#define SMB2_DIALECT_0210 (0x0210)
#define SMB2_DIALECT_0300 (0x0300)
#define SMB2_DIALECT_0302 (0x0302)

smb2_conn_t SMB2Connect(vc_t vc, char *share, char *user, char *domain,
                        char *passwd);
/*
    Negotiate, authenticate and connect to the share on a circuit that is
    already open.  Returns NULL if the server did not answer SMB2 at all,
    which is the caller's cue to fall back; anything else that goes wrong
    throws, because by then the server has committed to SMB2 and there is
    nothing to fall back to.
*/

int SMB2OpenPrint(smb2_conn_t, char *name,
                  unsigned char fileid[16]);
/*
    Start a print job.  A print share takes work the same way a disc share
    takes a file - create it, write the data to it, close it - and the name
    is only what the queue will show.  The old protocol had a command of its
    own for this; nothing has implemented that in a very long time.
*/

int SMB2OpenPipe(smb2_conn_t, char *name, unsigned char fileid[16]);
/*
    Open one of the named pipes the IPC$ share offers.  Nothing on a pipe
    is a file: it is opened, spoken to, and closed.
*/

int SMB2Transceive(smb2_conn_t, unsigned char fileid[16],
                   const unsigned char *in, int in_len,
                   unsigned char *out, int out_max);
/*
    Send a request down a pipe and collect the answer, which is one
    operation rather than a write and then a read.  Returns the length of
    the answer.  A pipe that had more to say than would fit says so with a
    status of its own, which is not an error and is treated as the end of
    what there was room for.
*/

void SMB2Disconnect(smb2_conn_t);

#define SMB2_FILEID_LEN (16)
/*
    SMB1 identified an open file by two bytes, which fitted in an int and
    was passed around as one.  SMB2 uses sixteen, so a handle can no longer
    be a number and has to be carried as itself.
*/

int SMB2Open(smb2_conn_t c, char *path, int directory, int writable,
             unsigned char fileid[SMB2_FILEID_LEN],
             unsigned int *size_low, unsigned int *size_high,
             unsigned int *attrs,
             unsigned int *write_low, unsigned int *write_high);
/*
    CREATE, which is open, create and stat in one exchange: the reply
    carries the times, the size and the attributes as well as the handle.
    path is relative to the share, with backslashes and no leading one; the
    share root is the empty string.  Returns 1, or throws.
*/

void SMB2Close(smb2_conn_t c, unsigned char fileid[SMB2_FILEID_LEN]);

int SMB2QueryDir(smb2_conn_t c, unsigned char fileid[SMB2_FILEID_LEN],
                 char *pattern, int restart,
                 unsigned char *out, int out_max);
/*
    One bufferful of directory entries, as FileBothDirectoryInformation -
    the same layout SMB1's find returned, so the existing decoder reads it
    unchanged.  Returns the number of bytes, or 0 once there are no more.
*/

int SMB2Read(smb2_conn_t c, unsigned char fileid[SMB2_FILEID_LEN],
             unsigned int off_low, unsigned int off_high,
             unsigned char *buf, int len);

int SMB2Write(smb2_conn_t c, unsigned char fileid[SMB2_FILEID_LEN],
              unsigned int off_low, unsigned int off_high,
              const unsigned char *buf, int len);

int SMB2MakeFile(smb2_conn_t c, char *path);

int SMB2MakeDir(smb2_conn_t c, char *path);

int SMB2Delete(smb2_conn_t c, char *path, int directory);
/*
    There is no delete request in SMB2: a file is opened with delete
    access, marked so that closing the handle takes it away, and closed.
*/

int SMB2Rename(smb2_conn_t c, char *path, char *newpath, int directory);
/*
    newpath is relative to the share, as path is, so this moves as well as
    renames depending on what is given.
*/

int SMB2SetEnd(smb2_conn_t c, unsigned char fileid[SMB2_FILEID_LEN],
               unsigned int low, unsigned int high);

int SMB2SetBasic(smb2_conn_t c, char *path, int directory,
                 unsigned int write_low, unsigned int write_high,
                 unsigned int attrs);
/*
    Last write time and attributes.  A time of zero leaves that one as it
    was, which is how only one of them can be changed.
*/

void SMB2Echo(smb2_conn_t c);

int SMB2FsInfo(smb2_conn_t c, unsigned int *total, unsigned int *avail,
               unsigned int *unit);

int SMB2SelfTest(smb2_conn_t c, char *report, int report_max);
/*
    Exercise the operations above against the connected share and describe
    what happened.  Scaffolding, so that each one can be shown to work on
    the wire before any of it is put under the filing system.
*/

int SMB2Dialect(smb2_conn_t);

unsigned int SMB2MaxRead(smb2_conn_t);

unsigned int SMB2MaxWrite(smb2_conn_t);

unsigned int SMB2MaxTransact(smb2_conn_t);
/*
    The most a single reply may carry that is neither a read nor a write -
    a directory listing, in practice.  Clamped both to what the server said
    it would send and to what the packet buffer can actually receive, which
    are not the same thing and neither of which may be assumed.
*/

#endif
