/*
                                  NETWOX
                             Network toolbox
                Copyright(c) 1999-2005 Laurent Constantin
                                  -----

  Main server    : http://www.laurentconstantin.com/
  Backup servers : http://go.to/laurentconstantin/
                   http://laurentconstantin.est-la.com/
                   http://laurentconstantin.free.fr/
                   http://membres.lycos.fr/lauconstantin/
  [my current email address is on the web servers]

                                  -----
  This file is part of Netwox.

  Netwox is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  version 2 as published by the Free Software Foundation.

  Netwox 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 (http://www.gnu.org/).

------------------------------------------------------------------------
*/

/*-------------------------------------------------------------*/
#include "../netwox.h"

/*-------------------------------------------------------------*/
netwib_err netwox_smbcmdtscq_init(netwox_smbcmdtscq *psmbcmdtscq)
{
  psmbcmdtscq->type = NETWOX_SMBCMDTSCQ_TYPE_UNKNOWN;
  return(NETWIB_ERR_OK);
}

/*-------------------------------------------------------------*/
netwib_err netwox_smbcmdtscq_selecttype(netwox_smbcmdtscq *psmbcmdtscq,
                                        netwox_smbcmdtscq_type type)
{

  if (psmbcmdtscq->type != NETWOX_SMBCMDTSCQ_TYPE_UNKNOWN) {
    return(NETWOX_ERR_INTERNALERROR);
  }

  psmbcmdtscq->type = type;
  switch(type) {
  case NETWOX_SMBCMDTSCQ_TYPE_NETSHAREENUM :
    netwib_er(netwox_smbcmdcmn_data_initdefault(&psmbcmdtscq->value.netshareenum.parameterdescriptor));
    netwib_er(netwox_smbcmdcmn_data_initdefault(&psmbcmdtscq->value.netshareenum.returndescriptor));
    break;
  default :
    psmbcmdtscq->type = NETWOX_SMBCMDTSCQ_TYPE_UNKNOWN;
    return(NETWIB_ERR_PAINVALIDTYPE);
  }

  return(NETWIB_ERR_OK);
}

/*-------------------------------------------------------------*/
netwib_err netwox_smbcmdtscq_setdefault(netwox_smbcmdtscq *psmbcmdtscq)
{

  switch(psmbcmdtscq->type) {
  case NETWOX_SMBCMDTSCQ_TYPE_NETSHAREENUM :
    netwib_er(netwox_smbcmdcmn_data_setdefault(&psmbcmdtscq->value.netshareenum.parameterdescriptor));
    netwib_er(netwox_smbcmdcmn_data_setdefault(&psmbcmdtscq->value.netshareenum.returndescriptor));
    psmbcmdtscq->value.netshareenum.detaillevel = 1;
    psmbcmdtscq->value.netshareenum.receivebufferlen = 4096;
    break;
  default :
    return(NETWIB_ERR_PAINVALIDTYPE);
  }

  return(NETWIB_ERR_OK);
}

/*-------------------------------------------------------------*/
netwib_err netwox_smbcmdtscq_close(netwox_smbcmdtscq *psmbcmdtscq)
{

  switch(psmbcmdtscq->type) {
  case NETWOX_SMBCMDTSCQ_TYPE_UNKNOWN :
    break;
  case NETWOX_SMBCMDTSCQ_TYPE_NETSHAREENUM :
    netwib_er(netwox_smbcmdcmn_data_close(&psmbcmdtscq->value.netshareenum.parameterdescriptor));
    netwib_er(netwox_smbcmdcmn_data_close(&psmbcmdtscq->value.netshareenum.returndescriptor));
    break;
  default :
    return(NETWIB_ERR_PAINVALIDTYPE);
  }

  return(NETWIB_ERR_OK);
}

/*-------------------------------------------------------------*/
/* There are 2 kinds of queries (perhaps more) : it depends on
   psmbcmd->value.transaction_q.name
     NETWOX_SMBCMD_TRANSACTION_NAME_PIPE (_p)
     NETWOX_SMBCMD_TRANSACTION_NAME_PIPELANMAN (_plm)
   They both have their sub command numbering
 */
typedef enum {
  NETWOX_SMBCMDTSCQ_P_SUBCMD_DCERPCNMPIPE = 38 /* complex to implement, and I'm
                                                  not sure it's really
                                                  needed */
} netwox_smbcmdtscq_p_subcmd;
typedef enum {
  NETWOX_SMBCMDTSCQ_PLM_SUBCMD_NETSHAREENUM = 0,
  NETWOX_SMBCMDTSCQ_PLM_SUBCMD_NETSHAREGETINFO = 1 /* not implemented, because
                                                      it seems to be only used
                                                      for errors */
} netwox_smbcmdtscq_plm_subcmd;

/*-------------------------------------------------------------*/
static netwib_err netwox_smbcmdtscq_encode_tsc_p(const netwox_smbcmd_transaction_q *ptsc,
                                             netwox_smbcmdtscq *psmbcmdtscq)
{
  netwib_data para, data;
  netwib_uint32 parasize, datasize;
  netwox_smbcmdtscq_p_subcmd subcmd;

  para = netwib__buf_ref_data_ptr(&ptsc->para);
  parasize = netwib__buf_ref_data_size(&ptsc->para);
  data = netwib__buf_ref_data_ptr(&ptsc->data);
  datasize = netwib__buf_ref_data_size(&ptsc->data);

  if (ptsc->setupcount == 0) {
    return(NETWIB_ERR_DATAMISSING);
  }
  subcmd = ptsc->setup[0];

  switch(subcmd) {
  case NETWOX_SMBCMDTSCQ_P_SUBCMD_DCERPCNMPIPE :
    return(NETWOX_ERR_NOTIMPLEMENTED);
  default :
    return(NETWIB_ERR_NOTCONVERTED);
  }

  return(NETWIB_ERR_OK);
  psmbcmdtscq = psmbcmdtscq;
}

/*-------------------------------------------------------------*/
static netwib_err netwox_smbcmdtscq_encode_tsc_plm(const netwox_smbcmd_transaction_q *ptsc,
                                             netwox_smbcmdtscq *psmbcmdtscq)
{
  netwib_data para, data;
  netwib_uint32 parasize, datasize;
  netwox_smbcmdtscq_plm_subcmd subcmd;

  para = netwib__buf_ref_data_ptr(&ptsc->para);
  parasize = netwib__buf_ref_data_size(&ptsc->para);
  data = netwib__buf_ref_data_ptr(&ptsc->data);
  datasize = netwib__buf_ref_data_size(&ptsc->data);

  if (parasize < 2) {
    return(NETWIB_ERR_DATAMISSING);
  }
  netwib__data_decode_uint16_le(para, subcmd);
  parasize -= 2;

  switch(subcmd) {
  case NETWOX_SMBCMDTSCQ_PLM_SUBCMD_NETSHAREENUM :
    netwib_er(netwox_smbcmdtscq_selecttype(psmbcmdtscq, NETWOX_SMBCMDTSCQ_TYPE_NETSHAREENUM));
    if (datasize) {
      return(NETWIB_ERR_NOTCONVERTED);
    }
    if (ptsc->setupcount) {
      return(NETWIB_ERR_NOTCONVERTED);
    }
    netwib_er(netwox_smbcmdcmn_data_decodestr(&para, &parasize, NETWIB_FALSE, &psmbcmdtscq->value.netshareenum.parameterdescriptor));
    netwib_er(netwox_smbcmdcmn_data_decodestr(&para, &parasize, NETWIB_FALSE, &psmbcmdtscq->value.netshareenum.returndescriptor));
    if (parasize != 4) {
      return(NETWIB_ERR_NOTCONVERTED);
    }
    netwib__data_decode_uint16_le(para, psmbcmdtscq->value.netshareenum.detaillevel);
    netwib__data_decode_uint16_le(para, psmbcmdtscq->value.netshareenum.receivebufferlen);
    break;
  case NETWOX_SMBCMDTSCQ_PLM_SUBCMD_NETSHAREGETINFO :
    return(NETWOX_ERR_NOTIMPLEMENTED);
  default :
    return(NETWIB_ERR_NOTCONVERTED);
  }

  return(NETWIB_ERR_OK);
}

/*-------------------------------------------------------------*/
netwib_err netwox_smbcmdtscq_encode_smbcmd(netwox_constsmbcmd *psmbcmd,
                                           netwox_smbcmdtscq *psmbcmdtscq)
{
  netwib_buf buftocmp, bufstr;
  netwib_byte array[80];
  netwib_data name;
  netwib_uint32 namesize;
  netwib_cmp cmp;

  if (psmbcmd->type != NETWOX_SMBCMD_TYPE_TRANSACTION_Q) {
    return(NETWIB_ERR_PAINVALIDTYPE);
  }
  if (netwib__buf_ref_data_size(&psmbcmd->value.transaction_q.para) != psmbcmd->value.transaction_q.totalparasize) {
    return(NETWIB_ERR_NOTCONVERTED);
  }
  if (netwib__buf_ref_data_size(&psmbcmd->value.transaction_q.data) != psmbcmd->value.transaction_q.totaldatasize) {
    return(NETWIB_ERR_NOTCONVERTED);
  }
  if (psmbcmd->value.transaction_q.setupcount > NETWOX_SMBCMD_TRANSACTION_SETUP_MAX) {
    return(NETWIB_ERR_NOTCONVERTED);
  }

  name = netwib__buf_ref_data_ptr(&psmbcmd->value.transaction_q.name);
  namesize = netwib__buf_ref_data_size(&psmbcmd->value.transaction_q.name);

  if (psmbcmd->value.transaction_q.isunicode) {
    netwib_er(netwib_buf_init_ext_text(NETWOX_SMBCMD_TRANSACTION_NAME_PIPELANMAN, &bufstr));
    netwib_er(netwib_buf_init_ext_arrayempty(array, sizeof(array), &buftocmp));
    netwib_er(netwox_buf_decode_ucs2le(&bufstr, &buftocmp));
    netwib_er(netwib_buf_cmp(&psmbcmd->value.transaction_q.name, &buftocmp,
                             &cmp));
    if (cmp == NETWIB_CMP_EQ) {
      netwib_er(netwox_smbcmdtscq_encode_tsc_plm(&psmbcmd->value.transaction_q, psmbcmdtscq));
      return(NETWIB_ERR_OK);
    }
    netwib_er(netwib_buf_init_ext_text(NETWOX_SMBCMD_TRANSACTION_NAME_PIPE,
                                       &bufstr));
    netwib_er(netwib_buf_init_ext_arrayempty(array, sizeof(array), &buftocmp));
    netwib_er(netwox_buf_decode_ucs2le(&bufstr, &buftocmp));
    netwib_er(netwib_buf_cmp(&psmbcmd->value.transaction_q.name, &buftocmp,
                             &cmp));
    if (cmp == NETWIB_CMP_EQ) {
      netwib_er(netwox_smbcmdtscq_encode_tsc_p(&psmbcmd->value.transaction_q, psmbcmdtscq));
      return(NETWIB_ERR_OK);
    }
  } else {
    netwib_er(netwib_buf_init_ext_text(NETWOX_SMBCMD_TRANSACTION_NAME_PIPELANMAN, &buftocmp));
    netwib_er(netwib_buf_cmp(&psmbcmd->value.transaction_q.name, &buftocmp,
                             &cmp));
    if (cmp == NETWIB_CMP_EQ) {
      netwib_er(netwox_smbcmdtscq_encode_tsc_plm(&psmbcmd->value.transaction_q, psmbcmdtscq));
      return(NETWIB_ERR_OK);
    }
    netwib_er(netwib_buf_init_ext_text(NETWOX_SMBCMD_TRANSACTION_NAME_PIPE,
                                       &buftocmp));
    netwib_er(netwib_buf_cmp(&psmbcmd->value.transaction_q.name, &buftocmp,
                             &cmp));
    if (cmp == NETWIB_CMP_EQ) {
      netwib_er(netwox_smbcmdtscq_encode_tsc_p(&psmbcmd->value.transaction_q, psmbcmdtscq));
      return(NETWIB_ERR_OK);
    }
  }

  return(NETWIB_ERR_NOTCONVERTED);
}

/*-------------------------------------------------------------*/
netwib_err netwox_smbcmdtscq_decode_smbcmd(netwox_constsmbcmdtscq *psmbcmdtscq,
                                           netwox_smbcmd *psmbcmd)
{
  netwib_data para;
  netwib_buf bufstr;

  switch(psmbcmdtscq->type) {
  case NETWOX_SMBCMDTSCQ_TYPE_NETSHAREENUM :
    if (psmbcmd->value.transaction_q.isunicode) {
      netwib_er(netwib_buf_init_ext_text(NETWOX_SMBCMD_TRANSACTION_NAME_PIPELANMAN, &bufstr));
      netwib_er(netwox_buf_decode_ucs2le(&bufstr, &psmbcmd->value.transaction_q.name));
    } else {
      netwib_er(netwib_buf_append_text(NETWOX_SMBCMD_TRANSACTION_NAME_PIPELANMAN, &psmbcmd->value.transaction_q.name));
    }
    netwib_er(netwib_buf_wantspace(&psmbcmd->value.transaction_q.para, 2, &para));
    netwib__data_append_uint16_le(para, NETWOX_SMBCMDTSCQ_PLM_SUBCMD_NETSHAREENUM);
    psmbcmd->value.transaction_q.para.endoffset += 2;
    netwib_er(netwox_smbcmdcmn_data_appendstr(&psmbcmdtscq->value.netshareenum.parameterdescriptor, NETWIB_FALSE, &psmbcmd->value.transaction_q.para));
    netwib_er(netwox_smbcmdcmn_data_appendstr(&psmbcmdtscq->value.netshareenum.returndescriptor, NETWIB_FALSE, &psmbcmd->value.transaction_q.para));
    netwib_er(netwib_buf_wantspace(&psmbcmd->value.transaction_q.para, 4, &para));
    netwib__data_append_uint16_le(para, psmbcmdtscq->value.netshareenum.detaillevel);
    netwib__data_append_uint16_le(para, psmbcmdtscq->value.netshareenum.receivebufferlen);
    psmbcmd->value.transaction_q.para.endoffset += 4;
    psmbcmd->value.transaction_q.totalparasize = (netwib_uint16)netwib__buf_ref_data_size(&psmbcmd->value.transaction_q.para);
    psmbcmd->value.transaction_q.totaldatasize = (netwib_uint16)netwib__buf_ref_data_size(&psmbcmd->value.transaction_q.data);
    break;
  default :
    return(NETWIB_ERR_PAINVALIDTYPE);
  }

  return(NETWIB_ERR_OK);
}

/*-------------------------------------------------------------*/
netwib_err netwox_smbcmdtscq_show(netwox_constsmbcmdtscq *psmbcmdtscq,
                                 netwib_buf *pbuf)
{

  switch(psmbcmdtscq->type) {
  case NETWOX_SMBCMDTSCQ_TYPE_NETSHAREENUM :
    netwib_er(netwib_show_array_fmt32(pbuf, " Net Share Enum Query"));
    netwib_er(netwox_smbcmdcmn_data_show(" parameterdescriptor", NETWOX_SMBCMDCMN_DATATYPE_STRINGONLY_NOUNI, &psmbcmdtscq->value.netshareenum.parameterdescriptor, pbuf));
    netwib_er(netwox_smbcmdcmn_data_show(" returndescriptor", NETWOX_SMBCMDCMN_DATATYPE_STRINGONLY_NOUNI, &psmbcmdtscq->value.netshareenum.returndescriptor, pbuf));
    netwib_er(netwib_show_array_fmt32(pbuf, " detaillevel=%{uint16}", psmbcmdtscq->value.netshareenum.detaillevel));
    netwib_er(netwib_show_array_fmt32(pbuf, " receivebufferlen=%{uint16}", psmbcmdtscq->value.netshareenum.receivebufferlen));
    break;
  default :
    return(NETWIB_ERR_PAINVALIDTYPE);
  }

  return(NETWIB_ERR_OK);
}
