/** BEGIN COPYRIGHT BLOCK
 * Copyright (C) 2001 Sun Microsystems, Inc.  Used by permission.
 * Copyright (C) 2005 Red Hat, Inc.
 * All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation version
 * 2.1 of the License.
 *                                                                                  
 * This library 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
 * Lesser General Public License for more details.
 *                                                                                  
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 * END COPYRIGHT BLOCK **/
#include "secpwd_pvt.h"
#include "libadminutil/admutil.h"

/* This file is copy from old libsec to do password checking */

/*
 * NOTE:  The contents of this file are NOT used by the client.
 * (They are part of the security library as a whole, but they are
 * NOT USED BY THE CLIENT.)  Do not change things on behalf of the
 * client (like localizing strings), or add things that are only
 * for the client (put them elsewhere).  Clearly we need a better
 * way to organize things, but for now this will have to do.
 */

extern char custom_file[BIG_LINE];
extern char retried_token[BIG_LINE];

#ifdef XP_UNIX

#include <termios.h>
#include <stdio.h>

#if HAVE_UNISTD_H == 1
#include <unistd.h>
#endif

static void echoOff(int fd)
{
    if (isatty(fd)) {
        struct termios tio;
        tcgetattr(fd, &tio);
        tio.c_lflag &= ~ECHO;
        tio.c_cc[VKILL] = '\0';
        tcsetattr(fd, TCSAFLUSH, &tio);
    }
}

static void echoOn(int fd)
{
    if (isatty(fd)) {
        struct termios tio;
        tcgetattr(fd, &tio);
        tio.c_lflag |= ECHO;
        tio.c_cc[VKILL] = '\0';
        tcsetattr(fd, TCSAFLUSH, &tio);
    }
}



unsigned char *SEC_GetPassword(FILE *input, FILE *output, char *prompt,
                               PRBool (*ok)(unsigned char *))
{
    unsigned char phrase[256];
    int infd = fileno(input);
    int isTTY = isatty(infd);

    for (;;) {
      /* Prompt for password */
      if (isTTY) {
        fprintf(output, "%s", prompt);
        echoOff(infd);
      }
      if (NULL == fgets((char*) phrase, sizeof(phrase) - 1, input)) {
        continue;
      }
      if (isTTY) {
        fprintf(output, "\n");
        echoOn(infd);
      }
 
      /* stomp on newline */
      phrase[PL_strlen((char*)phrase)-1] = 0;
 
      /* 
       * Don't need to check for a weird password input here...
       * the password has already been set !!
       */

      return (unsigned char*) PL_strdup((char*)phrase);
    }
}

char *
ADM_GetPassword(char *prompt)
{
  return (char*)SEC_GetPassword(stdin, stdout, prompt, SEC_CheckPassword);
}

#endif        /* XP_UNIX */


PRBool SEC_CheckPassword(unsigned char *cp)
{
    int len;
    unsigned char *end;

    len = PL_strlen((char*)cp);
    if (len < 8) {
        return PR_FALSE;
    }
    end = cp + len;
    while (cp < end) {
        unsigned char ch = *cp++;
        if (!((ch >= 'A') && (ch <= 'Z')) &&
            !((ch >= 'a') && (ch <= 'z'))) {
            /* pass phrase has at least one non alphabetic in it */
            return PR_TRUE;
        }
    }
    return PR_FALSE;
}

PRBool SEC_BlindCheckPassword(unsigned char *cp)
{
    if (cp != NULL) {
        return PR_TRUE;
    }
    return PR_FALSE;
}

char*
getPassword_cb(PK11SlotInfo* slot, PRBool set, void *wincx)
{
  char *pw = NULL;
  char *prompt;
  char *pin_filename = NULL;
  char line[BIG_LINE];
  char *token_name = NULL;

  char *ptr;
  int tmp;

  FILE *custom_fileptr;
  FILE *pin_fileptr;

  /* For i18n, later ....
  prompt = PR_smprintf(XP_GetString(XP_SEC_ENTER_PWD),
                       PK11_GetTokenName(slot));
  */

  token_name = PK11_GetTokenName(slot);
  if(PL_strcmp(token_name, retried_token) != 0) {
  
    /* no retry on this token yet - try to get from file first */
    if((*custom_file != '\0') &&
       ((custom_fileptr = fopen(custom_file, "r")) != NULL)) {
      while(fgets(line, BIG_LINE, custom_fileptr)) {
        if(PL_strstr(line, "pinFile:") == line) {
          tmp = PL_strlen(line)-1;
          while((line[tmp] == ' ') || (line[tmp] == '\n'))
            tmp--;
          line[tmp+1] = '\0';
          ptr = PL_strchr(line, ':');
          for(tmp=1; ptr[tmp] == ' '; tmp++) {}
          pin_filename = &(ptr[tmp]);
        }
      }
      fclose(custom_fileptr);
    }
    if(pin_filename) {
      if((pin_fileptr = fopen(pin_filename, "r")) != NULL) {
        while(fgets(line, BIG_LINE, pin_fileptr)) {
          if(PL_strstr(line, token_name) == line) {
            tmp = PL_strlen(line)-1;
            while((line[tmp] == ' ') || (line[tmp] == '\n'))
              tmp--;
            line[tmp+1] = '\0';
            ptr = PL_strchr(line, ':');
            for(tmp=1; ptr[tmp] == ' '; tmp++) {}
            pw = PL_strdup(&(ptr[tmp]));
          }
        }
        fclose(pin_fileptr);
      }
    }
  }

  if(!pw) {
    /* could not read from pin file or file pin incorrect - prompt the user */
    prompt = PR_smprintf("Password for the %s SSL token:", PK11_GetTokenName(slot));
    if (NULL != prompt) {
      pw = (char*)SEC_GetPassword(stdin, stdout, prompt, SEC_CheckPassword);
      PR_smprintf_free(prompt);
    }
  }
  PL_strncpyz(retried_token, token_name, sizeof(retried_token));
  return pw;
}


/*
 * WIN32 definition of the ADM_GetPassword function
 */
#ifdef XP_WIN32
#define IDD_SIEPWD 111
#define IDEDIT 1000
#define IDTOKEN 1004
static char password[512];
static char pinprompt[512];
static char *_helpURL = NULL;

//--------------------------------------------------------------------------//
// borrowed from \msvc20\mfc\src\dlgcore.cpp                                //
//--------------------------------------------------------------------------//
void static CenterDialog(HWND hwndParent, HWND hwndDialog)
{
   RECT DialogRect;
   RECT ParentRect;
   POINT Point;
   int nWidth;
   int nHeight;
 
   // Determine if the main window exists. This can be useful when
   // the application creates the dialog box before it creates the
   // main window. If it does exist, retrieve its size to center
   // the dialog box with respect to the main window.
   if(hwndParent != NULL)
   {
      GetClientRect(hwndParent, &ParentRect);
   }
   else
   {
      // if main window does not exist, center with respect to desktop
      hwndParent = GetDesktopWindow();
      GetWindowRect(hwndParent, &ParentRect);
   }
 
   // get the size of the dialog box
   GetWindowRect(hwndDialog, &DialogRect);
 
   // calculate height and width for MoveWindow()
   nWidth = DialogRect.right - DialogRect.left;
   nHeight = DialogRect.bottom - DialogRect.top;
 
   // find center point and convert to screen coordinates
   Point.x = (ParentRect.right - ParentRect.left) / 2;
   Point.y = (ParentRect.bottom - ParentRect.top) / 2;

   ClientToScreen(hwndParent, &Point);
 
   // calculate new X, Y starting point
   Point.x -= nWidth / 2;
   Point.y -= nHeight / 2;
 
   MoveWindow(hwndDialog, Point.x, Point.y, nWidth, nHeight, FALSE);
}

static BOOL CALLBACK
PasswordDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
   switch(message)
   {
   case WM_INITDIALOG:
      CenterDialog(NULL, hDlg);
      SendDlgItemMessage(hDlg, IDEDIT, EM_SETLIMITTEXT, sizeof(password), 0);
      SetDlgItemText(hDlg, IDTOKEN, pinprompt);
      EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
      return(FALSE);

   case WM_COMMAND:
      if(LOWORD(wParam) == IDEDIT)
      {
         if(HIWORD(wParam) == EN_CHANGE)
         {
            if(GetDlgItemText(hDlg, IDEDIT, password, sizeof(password)) > 0)
               EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
            else
               EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
         }
      }
      else
      if(LOWORD(wParam) == IDOK)
      {
         GetDlgItemText(hDlg, IDEDIT, password, sizeof(password));
         EndDialog(hDlg, IDOK);
         return (TRUE);
      }
      else if(LOWORD(wParam) == IDCANCEL)
      {
         /* User hit "Cancel" - terminate ns-admin.exe */
         memset(password, 0, sizeof(password));
         EndDialog(hDlg, IDCANCEL);
         exit(0);
      }
      else if ((LOWORD(wParam) == IDHELP) && (_helpURL != NULL)) {
#define ADMSSLVIEWURL "start ..\\..\\bin\\base\\viewurl.exe "
         char *exec = PR_smprintf("%s%s", ADMSLVIEWURL, _helpURL);

         if (NULL != exec) {
           system(exec);
           PR_smprintf_free(exec);
         }
         PR_Free(_helpURL);
      }
   }
   return (FALSE);
}


char *ADM_GetPassword_wHelp(char *prompt, const char *helpURL) {
    int result;

    PL_strncpyz(pinprompt, prompt, sizeof(pinprompt));

    PR_Free(_helpURL);
    _helpURL = NULL;

    if (helpURL!=NULL) {
         _helpURL = PL_strdup(helpURL);
    }

    result = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SIEPWD), 
                       HWND_DESKTOP, (int (__stdcall *)(void))PasswordDialogProc);
    if (result == -1) {
        result = GetLastError();
        servssl_error("DialogBox failed (code %d)\n",
                      result);
        return NULL;
    }
    return (unsigned char*) PL_strdup((char*)password);    
}

char *ADM_GetPassword(char *prompt)
{
    return ADM_GetPassword_wHelp(prompt, NULL);
}

#endif
