/*
 * 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)
#define SMB2_DIALECT_0311 (0x0311)

smb2_conn_t SMB2Connect(vc_t vc, char *share, char *user, char *domain,
                        char *passwd, int allow_311);
/*
    Negotiate, authenticate and connect to the share on a circuit that is
    already open.  Returns NULL if the negotiate got nowhere, 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.

    allow_311 says whether 3.1.1 may be offered.  Zero asks for 3.0.2 and
    below, which is what a server that refused the 3.1.1 form is asked
    next - see SMB2Refused311.
*/

int SMB2Refused311(void);
/*
    Whether the last negotiate offered 3.1.1 and the server answered in
    SMB2 to refuse it.  Distinguishes a server that objects to the request
    from one that does not speak the protocol, which look identical from
    the outside: both come back as NULL.
*/

unsigned int SMB2LastStatus(void);
/*
    What the last negotiate was refused with, or zero if nothing that
    parsed came back.  For reporting; the decision is SMB2Refused311's.
*/

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 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
