/********************************************************************/ /** 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 #include #include #include #define INCL_ERROR_H #include #include #include #include #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); }