|
|
/********************************************************************/ /** 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); }
|