windows-nt/Source/XPSP1/NT/ds/netapi/netcmd/common/mutil.c

1029 lines
20 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/********************************************************************/
/** Microsoft LAN Manager **/
/** Copyright(c) Microsoft Corp., 1987-1990 **/
/********************************************************************/
/***
* mutil.c
* Message utility functions used by netcmd
*
* History:
* mm/dd/yy, who, comment
* 06/10/87, andyh, new code
* 04/05/88, andyh, created from util.c
* 10/31/88, erichn, uses OS2.H instead of DOSCALLS
* 01/04/89, erichn, filenames now MAX_PATH_LEN LONG
* 01/30/89, paulc, added GetMessageList
* 05/02/89, erichn, NLS conversion
* 05/11/89, erichn, moved misc stuff into LUI libs
* 06/08/89, erichn, canonicalization sweep
* 01/06/90, thomaspa, fix ReadPass off-by-one pwlen bug
* 03/02/90, thomaspa, add canon flag to ReadPass
* 02/20/91, danhi, change to use lm 16/32 mapping layer
* 03/19/91, robdu, support for lm21 dcr 954, general cleanup
*/
/* Include files */
#define INCL_NOCOMMON
#define INCL_DOSFILEMGR
#define INCL_DOSQUEUES
#define INCL_DOSMISC
#define INCL_ERRORS
#include <os2.h>
#include <lmcons.h>
#include <apperr.h>
#include <apperr2.h>
#define INCL_ERROR_H
#include <lmerr.h>
#include <stdio.h>
#include <stdlib.h>
#include <lui.h>
#include "netcmds.h"
#include "nettext.h"
#include "msystem.h"
/* Constants */
/* HandType */
#define FILE_HANDLE 0
#define DEVICE_HANDLE 1
#define CHAR_DEV 0x8000
#define FULL_SUPPORT 0x0080
#define STDOUT_DEVICE 0x0002
#define DESIRED_HAND_STATE (CHAR_DEV | FULL_SUPPORT | STDOUT_DEVICE)
/* External variables */
extern int YorN_Switch;
extern CPINFO CurrentCPInfo;
#define MAX_BUF_SIZE 4096
TCHAR ConBuf [MAX_BUF_SIZE];
/* Forward declarations */
DWORD
DosQHandType(
HANDLE hf,
PWORD pus1,
PWORD pus2
);
DWORD
GetPasswdStr(
LPTSTR buf,
DWORD buflen,
PDWORD len
);
/* Static variables */
static DWORD LastError = 0;
static TCHAR MsgBuffer[LITTLE_BUF_SIZE];
/*** InfoSuccess
*
* Just an entrypoint to InfoPrintInsHandle, used to avoid pushing
* the three args in every invocation. And there are a *lot*
* of invocations. Saves code space overall.
*/
VOID FASTCALL
InfoSuccess(
VOID
)
{
InfoPrintInsHandle(APE_Success, 0, g_hStdOut);
}
/***
* I n f o P r i n t
*
*/
VOID FASTCALL
InfoPrint(
DWORD msg
)
{
InfoPrintInsHandle(msg, 0, g_hStdOut);
}
/***
* I n f o P r i n t I n s
*
*/
VOID FASTCALL
InfoPrintIns(
DWORD msg,
DWORD nstrings
)
{
InfoPrintInsHandle(msg, nstrings, g_hStdOut);
}
/***
* I n f o P r i n t I n s T x t
*
* Calls InfoPrintInsHandle with supplementary text
*/
void FASTCALL
InfoPrintInsTxt(
DWORD msg,
LPTSTR text
)
{
IStrings[0] = text;
InfoPrintInsHandle(msg, 1, g_hStdOut);
}
/***
* I n f o P r i n t I n s H a n d l e
*
*/
void FASTCALL
InfoPrintInsHandle(
DWORD msg,
DWORD nstrings,
HANDLE hdl
)
{
PrintMessage(hdl, MESSAGE_FILENAME, msg, IStrings, nstrings);
}
/***
* P r i n t M e s s a g e
*
*/
DWORD FASTCALL
PrintMessage(
HANDLE outFileHandle,
TCHAR *msgFileName,
DWORD msg,
TCHAR *strings[],
DWORD nstrings
)
{
DWORD msg_len;
DWORD result;
result = DosGetMessageW(strings,
nstrings,
MsgBuffer,
LITTLE_BUF_SIZE,
msg,
msgFileName,
&msg_len);
if (result) /* if there was a problem */
{ /* change outFile to stderr */
outFileHandle = g_hStdErr;
}
DosPutMessageW(outFileHandle, MsgBuffer, TRUE);
return result;
}
/***
* P r i n t M e s s a g e I f F o u n d
*
*/
DWORD FASTCALL
PrintMessageIfFound(
HANDLE outFileHandle,
TCHAR *msgFileName,
DWORD msg,
TCHAR * strings[],
DWORD nstrings
)
{
DWORD msg_len;
DWORD result;
result = DosGetMessageW(strings,
nstrings,
MsgBuffer,
LITTLE_BUF_SIZE,
msg,
msgFileName,
&msg_len);
if (!result) /* if ok, print it else just ignore */
{
DosPutMessageW(outFileHandle, MsgBuffer, TRUE);
}
return result;
}
/***
* E r r o r P r i n t
*
* nstrings ignored for non-NET errors!
*
*/
VOID FASTCALL
ErrorPrint(
DWORD err,
DWORD nstrings
)
{
TCHAR buf[17];
DWORD oserr = 0;
LastError = err; /* if > NERR_BASE,NetcmdExit() prints a "more help" msg */
if (err < NERR_BASE || err > MAX_LANMAN_MESSAGE_ID)
{
IStrings[0] = _ultow(err, buf, 10);
nstrings = 1;
oserr = err;
err = APE_OS2Error;
}
{
DWORD msg_len;
DosGetMessageW(IStrings,
nstrings,
MsgBuffer,
LITTLE_BUF_SIZE,
err,
MESSAGE_FILENAME,
&msg_len);
DosPutMessageW(g_hStdErr, MsgBuffer, TRUE);
if (!oserr)
{
return;
}
DosGetMessageW(StarStrings,
9,
MsgBuffer,
LITTLE_BUF_SIZE,
oserr,
OS2MSG_FILENAME,
&msg_len);
DosPutMessageW(g_hStdErr, MsgBuffer, TRUE);
}
}
/***
* E m p t y E x i t
*
* Prints a message and exits.
* Called when a list is empty.
*/
VOID FASTCALL
EmptyExit(
VOID
)
{
InfoPrint(APE_EmptyList);
NetcmdExit(0);
}
/***
* E r r o r E x i t
*
* Calls ErrorPrint and exit for a given LANMAN error.
*/
VOID FASTCALL
ErrorExit(
DWORD err
)
{
ErrorExitIns(err, 0);
}
/***
* E r r o r E x i t I n s
*
* Calls ErrorPrint and exit for a given LANMAN error.
* Uses IStrings.
*/
VOID FASTCALL
ErrorExitIns(
DWORD err,
DWORD nstrings
)
{
ErrorPrint(err, nstrings);
NetcmdExit(2);
}
/***
* E r r o r E x i t I n s T x t
*
*/
VOID FASTCALL
ErrorExitInsTxt(
DWORD err,
LPTSTR text
)
{
IStrings[0] = text;
ErrorPrint(err, 1);
NetcmdExit(2);
}
/***
* N e t c m d E x i t
*
* Net command exit function. Should always be used instead of exit().
* Under the appropriate circumstances, it prints a "more help available"
* message.
*/
VOID FASTCALL
NetcmdExit(
int Status
)
{
TCHAR AsciiLastError[17];
DWORD MsgLen;
if (LastError >= NERR_BASE && LastError <= MAX_LANMAN_MESSAGE_ID)
{
IStrings[0] = _ultow(LastError, AsciiLastError, 10);
if (!DosGetMessageW(IStrings, 1, MsgBuffer, LITTLE_BUF_SIZE,
APE_MoreHelp, MESSAGE_FILENAME, &MsgLen))
{
DosPutMessageW(g_hStdErr, MsgBuffer, TRUE);
}
}
MyExit(Status);
}
/***
* P r i n t L i n e
*
* Prints the header line.
*/
VOID FASTCALL
PrintLine(
VOID
)
{
/* The following code is provided in OS-specific versions to reduce */
/* FAPI utilization under DOS. */
USHORT type;
USHORT attrib;
if (DosQHandType((HANDLE) 1, &type, &attrib) ||
type != DEVICE_HANDLE ||
(attrib & DESIRED_HAND_STATE) != DESIRED_HAND_STATE)
{
WriteToCon(MSG_HYPHENS, NULL);
}
else if (LUI_PrintLine())
{
WriteToCon(MSG_HYPHENS, NULL);
}
}
/***
* P r i n t D o t
*
* Prints a dot, typically to indicate "I'm working".
*/
VOID FASTCALL
PrintDot(
VOID
)
{
WriteToCon(DOT_STRING, NULL);
}
/***
* P r i n t N L
*
* Prints a newline
*/
VOID FASTCALL
PrintNL(
VOID
)
{
WriteToCon(TEXT("\r\n"), NULL);
}
/***
* Y o r N
*
* Gets an answer to a Y/N question
* an nstrings arg would be nice
*/
int FASTCALL
YorN(
USHORT prompt,
USHORT def
)
{
DWORD err;
if (YorN_Switch)
{
return(YorN_Switch - 2);
}
err = LUI_YorN(prompt, def);
switch (err) {
case TRUE:
case FALSE:
break;
default:
ErrorExit(err);
break;
}
return err;
}
/***
* ReadPass()
* Reads a users passwd without echo
*
* Args:
* pass - where to put pass
* NOTE: buffer for pass should be passlen+1 in size.
* passlen - max length of password
* confirm - confirm pass if true
* prompt - prompt to print, NULL for default
* nstrings - number of insertion strings in IStrings on entry
* cannon - canonicalize password if true.
*
* Returns:
*/
VOID FASTCALL
ReadPass(
TCHAR pass[],
DWORD passlen,
DWORD confirm,
DWORD prompt,
DWORD nstrings,
BOOL canon
)
{
DWORD err;
DWORD len;
TCHAR cpass[PWLEN+1]; /* confirmation passwd */
int count;
passlen++; /* one extra for null terminator */
for (count = LOOP_LIMIT; count; count--)
{
InfoPrintIns((prompt ? prompt : APE_UtilPasswd), nstrings);
if (err = GetPasswdStr(pass, passlen, &len))
{
/* too LONG */
InfoPrint(APE_UtilInvalidPass);
continue;
}
if (canon && (err = LUI_CanonPassword(pass)))
{
/* not good */
InfoPrint(APE_UtilInvalidPass);
continue;
}
if (! confirm)
return;
/* password confirmation */
InfoPrint(APE_UtilConfirm);
if (err = GetPasswdStr(cpass, passlen, &len))
{
/* too LONG */
InfoPrint(APE_UtilInvalidPass);
ClearStringW(cpass) ;
continue;
}
if (canon && (err = LUI_CanonPassword(cpass)))
{
/* not good */
InfoPrint(APE_UtilInvalidPass);
ClearStringW(cpass) ;
continue;
}
if (_tcscmp(pass, cpass))
{
InfoPrint(APE_UtilNomatch);
ClearStringW(cpass) ;
continue;
}
ClearStringW(cpass) ;
return;
}
/***
* Only get here if user blew if LOOP_LIMIT times
*/
ErrorExit(APE_NoGoodPass);
}
/***
* PromptForString()
* Prompts the user for a string.
*
* Args:
* msgid - id of prompt message
* buffer - buffer to receive string
* bufsiz - sizeof buffer
*
* Returns:
*/
VOID FASTCALL
PromptForString(
DWORD msgid,
LPTSTR buffer,
DWORD bufsiz
)
{
DWORD err;
DWORD len;
TCHAR terminator;
TCHAR szLen[16] ;
InfoPrint(msgid);
while (err = GetString(buffer, bufsiz, &len, &terminator))
{
if (err == NERR_BufTooSmall)
{
InfoPrintInsTxt(APE_StringTooLong, _ultow(bufsiz, szLen, 10));
}
else
{
ErrorExit(err);
}
}
return;
}
/*
** There is no need to have these functions in the Chinese/Korean
** cases, as there are no half-width varients used in the console
** in those languages (at least, let's hope so.) However, in the
** interests of a single binary, let's put them in with a CP/932 check.
**
** FloydR 7/10/95
*/
/***************************************************************************\
* BOOL IsFullWidth(WCHAR wch)
*
* Determine if the given Unicode char is fullwidth or not.
*
* History:
* 04-08-92 ShunK Created.
\***************************************************************************/
BOOL IsFullWidth(WCHAR wch)
{
/* Assert cp == double byte codepage */
if (wch <= 0x007f || (wch >= 0xff60 && wch <= 0xff9f))
return(FALSE); // Half width.
else if (wch >= 0x300)
return(TRUE); // Full width.
else
return(FALSE); // Half width.
}
/***************************************************************************\
* DWORD SizeOfHalfWidthString(PWCHAR pwch)
*
* Determine width of the given Unicode string in console characters,
* adjusting for half-width chars.
*
* History:
* 08-08-93 FloydR Created.
\***************************************************************************/
DWORD
SizeOfHalfWidthString(
PWCHAR pwch
)
{
DWORD c=0;
DWORD cp;
switch (cp=GetConsoleOutputCP())
{
case 932:
case 936:
case 949:
case 950:
while (*pwch)
{
if (IsFullWidth(*pwch))
{
c += 2;
}
else
{
c++;
}
pwch++;
}
return c;
default:
return wcslen(pwch);
}
}
VOID FASTCALL
GetMessageList(
USHORT usNumMsg,
MESSAGELIST Buffer,
DWORD *pusMaxActLength
)
{
DWORD Err;
DWORD MaxMsgLen = 0;
MESSAGE *pMaxMsg;
MESSAGE *pMsg;
DWORD ThisMsgLen;
#ifdef DEBUG
USHORT MallocBytes = 0;
#endif
pMaxMsg = &Buffer[usNumMsg];
for (pMsg = Buffer; pMsg < pMaxMsg; pMsg++)
pMsg->msg_text = NULL;
for (pMsg = Buffer; pMsg < pMaxMsg; pMsg++)
{
#ifdef DEBUG
WriteToCon(TEXT("GetMessageList(): Reading msgID %u\r\n"),pMsg->msg_number);
#endif
if ((pMsg->msg_text = malloc(MSGLST_MAXLEN)) == NULL)
ErrorExit(ERROR_NOT_ENOUGH_MEMORY);
Err = LUI_GetMsgInsW(NULL, 0, pMsg->msg_text, MSGLST_MAXLEN,
pMsg->msg_number, &ThisMsgLen);
if (Err)
{
ErrorExit(Err);
}
#ifdef DEBUG
MallocBytes += (ThisMsgLen + 1) * sizeof(TCHAR);
#endif
ThisMsgLen = max(ThisMsgLen, SizeOfHalfWidthString(pMsg->msg_text));
if (ThisMsgLen > MaxMsgLen)
MaxMsgLen = ThisMsgLen;
}
*pusMaxActLength = MaxMsgLen;
#ifdef DEBUG
WriteToCon(TEXT("GetMessageList(): NumMsg = %d, MaxActLen=%d, MallocBytes = %d\r\n"),
usNumMsg, MaxMsgLen, MallocBytes);
#endif
return;
}
VOID FASTCALL
FreeMessageList(
USHORT usNumMsg,
MESSAGELIST MsgList
)
{
USHORT i;
for (i = 0; i < usNumMsg; i++)
{
if (MsgList[i].msg_text != NULL)
{
free(MsgList[i].msg_text);
}
}
return;
}
VOID
WriteToCon(
LPWSTR fmt,
...
)
{
va_list args;
va_start( args, fmt );
_vsntprintf( ConBuf, MAX_BUF_SIZE, fmt, args );
va_end( args );
DosPutMessageW(g_hStdOut, ConBuf, FALSE);
}
/***************************************************************************\
* PWCHAR PaddedString(DWORD size, PWCHAR pwch)
*
* Realize the string, left aligned and padded on the right to the field
* width/precision specified.
*
* Limitations: This uses a static buffer under the assumption that
* no more than one such string is printed in a single 'printf'.
*
* History:
* 11-03-93 FloydR Created.
\***************************************************************************/
WCHAR PaddingBuffer[MAX_BUF_SIZE];
PWCHAR
PaddedString(
int size,
PWCHAR pwch,
PWCHAR buffer
)
{
int realsize;
int fEllipsis = FALSE;
if (buffer==NULL) buffer = PaddingBuffer;
if (size < 0) {
fEllipsis = TRUE;
size = -size;
}
//
// size is >= 0 at this point
//
realsize = _snwprintf(buffer, MAX_BUF_SIZE, L"%-*.*ws", size, size, pwch);
if (realsize == 0)
{
return NULL;
}
if (SizeOfHalfWidthString(buffer) > (DWORD) size)
{
do
{
buffer[--realsize] = NULLC;
} while (SizeOfHalfWidthString(buffer) > (DWORD) size);
if (fEllipsis && buffer[realsize-1] != L' ')
{
buffer[realsize-1] = L'.';
buffer[realsize-2] = L'.';
buffer[realsize-3] = L'.';
}
}
return buffer;
}
DWORD
DosQHandType(
HANDLE hf,
PWORD pus1,
PWORD pus2
)
{
DWORD dwFileType;
dwFileType = GetFileType(hf);
if (dwFileType == FILE_TYPE_CHAR)
{
*pus1 = DEVICE_HANDLE;
*pus2 = DESIRED_HAND_STATE;
}
else
{
*pus1 = FILE_HANDLE;
}
return(0);
}
/*** GetPasswdStr -- read in password string
*
* DWORD GetPasswdStr(char far *, USHORT);
*
* ENTRY: buf buffer to put string in
* buflen size of buffer
* &len address of USHORT to place length in
*
* RETURNS:
* 0 or NERR_BufTooSmall if user typed too much. Buffer
* contents are only valid on 0 return.
*
* History:
* who when what
* erichn 5/10/89 initial code
* dannygl 5/28/89 modified DBCS usage
* erichn 7/04/89 handles backspaces
* danhi 4/16/91 32 bit version for NT
*/
#define CR 0xD
#define BACKSPACE 0x8
DWORD
GetPasswdStr(
LPTSTR buf,
DWORD buflen,
PDWORD len
)
{
TCHAR ch;
TCHAR *bufPtr = buf;
DWORD c;
int err;
int mode;
buflen -= 1; /* make space for null terminator */
*len = 0; /* GP fault probe (a la API's) */
//
// Init mode in case GetConsoleMode() fails
//
mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT |
ENABLE_MOUSE_INPUT;
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),
(~(ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT)) & mode);
while (TRUE)
{
err = ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &ch, 1, &c, 0);
if (!err || c != 1)
{
ch = 0xffff;
}
if ((ch == CR) || (ch == 0xffff)) /* end of the line */
{
break;
}
if (ch == BACKSPACE) /* back up one or two */
{
/*
* IF bufPtr == buf then the next two lines are
* a no op.
*/
if (bufPtr != buf)
{
bufPtr--;
(*len)--;
}
}
else
{
*bufPtr = ch;
if (*len < buflen)
bufPtr++ ; /* don't overflow buf */
(*len)++; /* always increment len */
}
}
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode);
*bufPtr = NULLC; /* null terminate the string */
putchar(NEWLINE);
return ((*len <= buflen) ? 0 : NERR_BufTooSmall);
}
/*** GetString -- read in string with echo
*
* DWORD GetString(char far *, USHORT, USHORT far *, char far *);
*
* ENTRY: buf buffer to put string in
* buflen size of buffer
* &len address of USHORT to place length in
* &terminator holds the char used to terminate the string
*
* RETURNS:
* 0 or NERR_BufTooSmall if user typed too much. Buffer
* contents are only valid on 0 return. Len is ALWAYS valid.
*
* OTHER EFFECTS:
* len is set to hold number of bytes typed, regardless of
* buffer length. Terminator (Arnold) is set to hold the
* terminating character (newline or EOF) that the user typed.
*
* Read in a string a character at a time. Is aware of DBCS.
*
* History:
* who when what
* erichn 5/11/89 initial code
* dannygl 5/28/89 modified DBCS usage
* danhi 3/20/91 ported to 32 bits
*/
DWORD
GetString(
LPTSTR buf,
DWORD buflen,
PDWORD len,
LPTSTR terminator
)
{
int c;
int err;
buflen -= 1; /* make space for null terminator */
*len = 0; /* GP fault probe (a la API's) */
while (TRUE)
{
err = ReadConsole(GetStdHandle(STD_INPUT_HANDLE), buf, 1, &c, 0);
if (!err || c != 1)
*buf = 0xffff;
if (*buf == (TCHAR)EOF)
break;
if (*buf == RETURN || *buf == NEWLINE) {
INPUT_RECORD ir;
int cr;
if (PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &cr))
ReadConsole(GetStdHandle(STD_INPUT_HANDLE), buf, 1, &c, 0);
break;
}
buf += (*len < buflen) ? 1 : 0; /* don't overflow buf */
(*len)++; /* always increment len */
}
*terminator = *buf; /* set terminator */
*buf = NULLC; /* null terminate the string */
return ((*len <= buflen) ? 0 : NERR_BufTooSmall);
}