/* 
 *  Unix SMB/CIFS implementation.
 *  MS-RPC client library implementation
 *  Copyright (C) Chris Nicholls              2005.
 *  
 *  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.
 */

#include "libmsrpc.h"
#include "libmsrpc_internal.h"
#include "libsmbclient.h"
#include "libsmb_internal.h"

/*this function is based on code found in smbc_init_context() (libsmb/libsmbclient.c)*/
void cac_Init(int debug) {
   if(debug < 0 || debug > 99)
      debug = 0;

   DEBUGLEVEL = debug;

   setup_logging("libmsrpc", True);
}

int cac_InitHandleMem(CacServerHandle *hnd) {
   hnd->username       = SMB_MALLOC_ARRAY(char, sizeof(fstring));
   if(!hnd->username)
      return CAC_FAILURE;

   hnd->username[0] = '\0';

   hnd->domain         = SMB_MALLOC_ARRAY(char, sizeof(fstring));
   if(!hnd->domain)
      return CAC_FAILURE;
   
   hnd->domain[0] = '\0';

   hnd->netbios_name   = SMB_MALLOC_ARRAY(char, sizeof(fstring));
   if(!hnd->netbios_name)
      return CAC_FAILURE;

   hnd->netbios_name[0] = '\0';

   hnd->password       = SMB_MALLOC_ARRAY(char, sizeof(fstring));
   if(!hnd->password)
      return CAC_FAILURE;

   hnd->password[0] = '\0';

   hnd->server         = SMB_MALLOC_ARRAY(char, sizeof(fstring));
   if(!hnd->server)
      return CAC_FAILURE;

   hnd->server[0] = '\0';

   return CAC_SUCCESS;
}

CacServerHandle *cac_NewServerHandle(BOOL allocate_fields) {
   CacServerHandle * hnd;

   hnd = SMB_MALLOC_P(CacServerHandle);

   if(!hnd) {
      errno = ENOMEM;
      return NULL;
   }
   
   ZERO_STRUCTP(hnd);

   if(allocate_fields == True) {
      if(!cac_InitHandleMem(hnd)) {
         SAFE_FREE(hnd);
         return NULL;
      }
   }

   hnd->_internal.ctx = smbc_new_context();
   if(!hnd->_internal.ctx) {
      cac_FreeHandle(hnd);
      return NULL;
   }

   hnd->_internal.ctx->callbacks.auth_fn = cac_GetAuthDataFn;
   
   /*add defaults*/
   hnd->debug = 0;

   /*start at the highest and it will fall down after trying the functions*/
   hnd->_internal.srv_level = SRV_WIN_2K3;

   hnd->_internal.user_supplied_ctx = False;

   return hnd;
}

int cac_InitHandleData(CacServerHandle *hnd) {
   /*store any automatically initialized values*/
   if(!hnd->netbios_name) {
      hnd->netbios_name = SMB_STRDUP(hnd->_internal.ctx->netbios_name);
   }
   else if(hnd->netbios_name[0] == '\0') {
      strncpy(hnd->netbios_name, hnd->_internal.ctx->netbios_name, sizeof(fstring));
   }

   if(!hnd->username) {
      hnd->username = SMB_STRDUP(hnd->_internal.ctx->user);
   }
   else if(hnd->username[0] == '\0') {
      strncpy(hnd->username, hnd->_internal.ctx->user, sizeof(fstring));
   }

   if(!hnd->domain) {
      hnd->domain = SMB_STRDUP(hnd->_internal.ctx->workgroup);
   }
   else if(hnd->domain[0] == '\0') {
      strncpy(hnd->domain, hnd->_internal.ctx->workgroup, sizeof(fstring));
   }

   return CAC_SUCCESS;
}

void cac_SetAuthDataFn(CacServerHandle *hnd, smbc_get_auth_data_fn auth_fn) {
   hnd->_internal.ctx->callbacks.auth_fn = auth_fn;
}

void cac_SetSmbcContext(CacServerHandle *hnd, SMBCCTX *ctx) {

   SAFE_FREE(hnd->_internal.ctx);

   hnd->_internal.user_supplied_ctx = True;

   hnd->_internal.ctx = ctx;

   /*_try_ to avoid any problems that might occur if cac_Connect() isn't called*/
   /*cac_InitHandleData(hnd);*/
}

/*used internally*/
SMBCSRV *cac_GetServer(CacServerHandle *hnd) {
   SMBCSRV *srv;

   if(!hnd || !hnd->_internal.ctx) {
      return NULL;
   }

   srv = smbc_attr_server(hnd->_internal.ctx, hnd->server, "IPC$", hnd->domain, hnd->username, hnd->password, NULL);
   if(!srv) {
      hnd->status=NT_STATUS_UNSUCCESSFUL;
      DEBUG(1, ("cac_GetServer: Could not find server connection.\n"));
   }

   return srv;
}


int cac_Connect(CacServerHandle *hnd, const char *srv) {
   if(!hnd) {
      return CAC_FAILURE;
   }

   /*these values should be initialized by the user*/
   if(!hnd->server && !srv) {
      return CAC_FAILURE;
   }


   /*change the server name in the server handle if necessary*/
   if(srv && hnd->server && strcmp(hnd->server, srv) == 0) {
      SAFE_FREE(hnd->server);
      hnd->server = SMB_STRDUP(srv);
   }


   /*first see if the context has already been setup*/
   if( !(hnd->_internal.ctx->internal->_initialized) ) {
      hnd->_internal.ctx->debug = hnd->debug;

      /*initialize the context*/
      if(!smbc_init_context(hnd->_internal.ctx)) {
         return CAC_FAILURE;
      }
   }

   /*copy any uninitialized values out of the smbc context into the handle*/
   if(!cac_InitHandleData(hnd)) {
      return CAC_FAILURE;
   }

   DEBUG(3, ("cac_Connect: Username:     %s\n", hnd->username));
   DEBUG(3, ("cac_Connect: Domain:       %s\n", hnd->domain));
   DEBUG(3, ("cac_Connect: Netbios Name: %s\n", hnd->netbios_name));

   if(!cac_GetServer(hnd)) {
      return CAC_FAILURE;
   }
   
   return CAC_SUCCESS;
                                     
}


void cac_FreeHandle(CacServerHandle * hnd) {
   if(!hnd)
      return;

   /*only free the context if we created it*/
   if(!hnd->_internal.user_supplied_ctx) {
      smbc_free_context(hnd->_internal.ctx, True);
   }

   SAFE_FREE(hnd->netbios_name);
   SAFE_FREE(hnd->domain);
   SAFE_FREE(hnd->username);
   SAFE_FREE(hnd->password);
   SAFE_FREE(hnd->server);
   SAFE_FREE(hnd);

}

void cac_InitCacTime(CacTime *cactime, NTTIME nttime) {
   float high, low;
   uint32 sec;

   if(!cactime)
      return;

   ZERO_STRUCTP(cactime);

   /*this code is taken from display_time() found in rpcclient/cmd_samr.c*/
   if (nttime.high==0 && nttime.low==0)
		return;

	if (nttime.high==0x80000000 && nttime.low==0)
		return;

	high = 65536;	
	high = high/10000;
	high = high*65536;
	high = high/1000;
	high = high * (~nttime.high);

	low = ~nttime.low;	
	low = low/(1000*1000*10);

	sec=high+low;

	cactime->days=sec/(60*60*24);
	cactime->hours=(sec - (cactime->days*60*60*24)) / (60*60);
	cactime->minutes=(sec - (cactime->days*60*60*24) - (cactime->hours*60*60) ) / 60;
	cactime->seconds=sec - (cactime->days*60*60*24) - (cactime->hours*60*60) - (cactime->minutes*60);
}

void cac_GetAuthDataFn(const char * pServer,
                 const char * pShare,
                 char * pWorkgroup,
                 int maxLenWorkgroup,
                 char * pUsername,
                 int maxLenUsername,
                 char * pPassword,
                 int maxLenPassword)
    
{
    char temp[sizeof(fstring)];
    
    static char authUsername[sizeof(fstring)];
    static char authWorkgroup[sizeof(fstring)];
    static char authPassword[sizeof(fstring)];
    static char authSet = 0;

    char *pass = NULL;

    
    if (authSet)
    {
        strncpy(pWorkgroup, authWorkgroup, maxLenWorkgroup - 1);
        strncpy(pUsername, authUsername, maxLenUsername - 1);
        strncpy(pPassword, authPassword, maxLenPassword - 1);
    }
    else
    {
        d_printf("Domain: [%s] ", pWorkgroup);
        fgets(temp, sizeof(fstring), stdin);
        
        if (temp[strlen(temp) - 1] == '\n') /* A new line? */
        {
            temp[strlen(temp) - 1] = '\0';
        }
        

        if (temp[0] != '\0')
        {
            strncpy(pWorkgroup, temp, maxLenWorkgroup - 1);
            strncpy(authWorkgroup, temp, maxLenWorkgroup - 1);
        }
        
        d_printf("Username: [%s] ", pUsername);
        fgets(temp, sizeof(fstring), stdin);
        
        if (temp[strlen(temp) - 1] == '\n') /* A new line? */
        {
            temp[strlen(temp) - 1] = '\0';
        }
        
        if (temp[0] != '\0')
        {
            strncpy(pUsername, temp, maxLenUsername - 1);
            strncpy(authUsername, pUsername, maxLenUsername - 1);
        }
        
        pass = getpass("Password: ");
        if (pass)
            fstrcpy(temp, pass);
        if (temp[strlen(temp) - 1] == '\n') /* A new line? */
        {
            temp[strlen(temp) - 1] = '\0';
        }        
        if (temp[0] != '\0')
        {
            strncpy(pPassword, temp, maxLenPassword - 1);
            strncpy(authPassword, pPassword, maxLenPassword - 1);
        }        
        authSet = 1;
    }
}