/*
                                  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_smbserver_init(netwox_sockinfo *psockinfo,
                                 netwox_smbserver *psmbserver)
{
  /* those can be changed by users */
  psmbserver->maxwaitms = 180000;
  psmbserver->pallowedclients = NULL;
  netwib_er(netwib_buf_init_ext_empty(&psmbserver->user));
  psmbserver->user.flags |= NETWIB_BUF_FLAGS_CANALLOC;
  netwib_er(netwib_buf_init_ext_empty(&psmbserver->password));
  psmbserver->password.flags |= NETWIB_BUF_FLAGS_CANALLOC;
  netwib_er(netwib_buf_init_ext_empty(&psmbserver->share));
  psmbserver->share.flags |= NETWIB_BUF_FLAGS_CANALLOC;
  netwib_er(netwib_buf_init_ext_empty(&psmbserver->rootdir));
  psmbserver->rootdir.flags |= NETWIB_BUF_FLAGS_CANALLOC;
  netwib_er(netwib_buf_append_text(".", &psmbserver->rootdir));
  psmbserver->allowput = NETWIB_TRUE;
  psmbserver->debug = NETWIB_FALSE;
  psmbserver->verbose = NETWIB_FALSE;

  /* internal */
  netwib_er(netwib_bufpool_init(NETWIB_TRUE, &psmbserver->pbufpool));

  switch(psockinfo->localport) {
  case NETWOX_SERVICES_SMBNBTSS :
    psmbserver->isnaked = NETWIB_FALSE;
    break;
  case NETWOX_SERVICES_SMBNAKED :
    psmbserver->isnaked = NETWIB_TRUE;
    break;
  default :
    /* don't know if this is correct */
    psmbserver->isnaked = NETWIB_TRUE;
    break;
  }

  return(NETWIB_ERR_OK);
}

/*-------------------------------------------------------------*/
netwib_err netwox_smbserver_close(netwox_smbserver *psmbserver)
{
  netwib_er(netwib_bufpool_close(&psmbserver->pbufpool));

  netwib_er(netwib_buf_close(&psmbserver->user));
  netwib_er(netwib_buf_close(&psmbserver->password));
  netwib_er(netwib_buf_close(&psmbserver->share));
  netwib_er(netwib_buf_close(&psmbserver->rootdir));

  return(NETWIB_ERR_OK);
}

/*-------------------------------------------------------------*/
static netwib_err netwox_priv_smbserver_reply(netwox_smbser *psmbser,
                                              netwox_constsmbmsg *psmbmsgq,
                                              netwox_constsmbcmd *psmbcmdq)
{

  switch(psmbcmdq->type) {
  case NETWOX_SMBCMD_TYPE_NEGOTIATE_Q :
    netwib_er(netwox_smbser_negotiate(psmbser, psmbcmdq));
    break;
  default :
    psmbser->smberrtosend = NETWOX_SMBERR_NOTIMPLEMENTED;
  }

  return(NETWIB_ERR_OK);
  psmbmsgq = psmbmsgq;
}

/*-------------------------------------------------------------*/
static netwib_err netwox_smbserver_session2(netwib_io *psockio,
                                            netwox_smbser *psmbser)
{
  netwib_ip remoteip;
  netwib_port remoteport;
  netwib_bool allowed;
  netwox_smbmsg smbmsgq;
  netwox_smbcmd smbcmdq;
  netwib_uint32 i;
  netwib_err ret;

  /* check allowed clients */
  allowed = NETWIB_TRUE;
  if (psmbser->pcommon->pallowedclients != NULL) {
    netwib_er(netwib_sock_ctl_get_remote(psockio, &remoteip, &remoteport));
    netwib_er(netwib_ips_contains_ip(psmbser->pcommon->pallowedclients,
                                     &remoteip, &allowed));
  }
  if (!allowed) {
    netwib_er(netwib_fmt_display("IP address %{ip} is not allowed\n",
                                 &remoteip));
    return(NETWIB_ERR_OK);
  }

  /* loop for each received message, and analyze every command */
  ret = NETWIB_ERR_OK;
  while(ret == NETWIB_ERR_OK) {
    /* receive a message */
    if (psmbser->pcommon->verbose) {
      netwib_er(netwib_fmt_display("Waiting for next message\n"));
    }
    netwib_er(netwox_smbmsg_init(&smbmsgq));
    ret = netwox_smbser_smbmsg_recv(psmbser, &smbmsgq);
    /* decode its commands */
    for (i = 0; i < smbmsgq.numcmds && ret == NETWIB_ERR_OK; i++) {
      psmbser->smberrtosend = NETWOX_SMBERR_OK;
      netwib_er(netwox_smbcmd_init(&smbcmdq));
      ret = netwox_smbmsg_decode_smbcmd(&smbmsgq, i, &smbcmdq);
      if (ret == NETWIB_ERR_OK) {
        if (psmbser->pcommon->verbose) {
          netwib_er(netwib_fmt_display("A message command is analyzed\n"));
        }
        ret = netwox_priv_smbserver_reply(psmbser, &smbmsgq, &smbcmdq);
      }
      /* send error, and ignore it */
      if (ret != NETWIB_ERR_OK || psmbser->smberrtosend != NETWOX_SMBERR_OK) {
        if (psmbser->smberrtosend == NETWOX_SMBERR_OK) {
          psmbser->smberrtosend = NETWOX_SMBERR_NOTIMPLEMENTED;
        }
        ret = netwox_smbser_smberr_send(psmbser, smbmsgq.cmds[i].cmd,
                                        psmbser->smberrtosend);
      }
      netwib_er(netwox_smbcmd_close(&smbcmdq));
    }
    netwib_er(netwox_smbmsg_close(&smbmsgq));
  }

  return(ret);
}

/*-------------------------------------------------------------*/
netwib_err netwox_smbserver_session(netwib_io *psockio,
                                    netwib_ptr pinfos)
{
  netwox_smbser smbser;
  netwib_err ret;

  /* init */
  netwib_er(netwox_smbser_init((netwox_constsmbserver *)pinfos, psockio,
                               &smbser));

  /* main */
  ret = netwox_smbserver_session2(psockio, &smbser);
  if (ret != NETWIB_ERR_OK) {
    netwib_er(netwox_err_display(ret, NETWIB_ERR_ENCODETYPE_TEXT));
  }

  /* close */
  netwib_er(netwox_smbser_close(&smbser));
  return(NETWIB_ERR_OK);
}
