mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
603 lines
13 KiB
603 lines
13 KiB
/********************************************************************/
|
|
/** Microsoft LAN Manager **/
|
|
/** Copyright(c) Microsoft Corp., 1987-1990 **/
|
|
/********************************************************************/
|
|
|
|
/***
|
|
* message.c
|
|
* Functions for message handling: forward, log, name, send.
|
|
*
|
|
* History:
|
|
* mm/dd/yy, who, comment
|
|
* 06/02/87, andyh, new code
|
|
* 10/31/88, erichn, uses OS2.H instead of DOSCALLS
|
|
* 01/04/89, erichn, filenames now MAXPATHLEN LONG
|
|
* 02/08/89, paulc, Net Send /DOMAIN and /BROADCAST mods
|
|
* 05/02/89, erichn, NLS conversion
|
|
* 05/09/89, erichn, local security mods
|
|
* 06/08/89, erichn, canonicalization sweep
|
|
* 02/20/91, danhi, change to use lm 16/32 mapping layer
|
|
*/
|
|
|
|
/* Include files */
|
|
|
|
#define INCL_NOCOMMON
|
|
#define INCL_DOSFILEMGR
|
|
#define INCL_ERRORS
|
|
#include <os2.h>
|
|
#include <lmcons.h>
|
|
#include <lmerr.h>
|
|
#include <lmapibuf.h>
|
|
#include <apperr.h>
|
|
#include <apperr2.h>
|
|
#include <lmmsg.h>
|
|
#include <lmshare.h>
|
|
#include <stdlib.h>
|
|
#include <dlwksta.h>
|
|
#include "mwksta.h"
|
|
#include <lui.h>
|
|
#include "netcmds.h"
|
|
#include "nettext.h"
|
|
|
|
/* Constants */
|
|
|
|
#define FROM_CMD_LINE 1
|
|
#define FROM_STDIN 2
|
|
|
|
#define TO_NAME 1
|
|
#define TO_GROUP 2 // no longer used
|
|
#define TO_USERS 3
|
|
#define TO_DOMAIN 4
|
|
#define TO_ALL 5
|
|
|
|
/* External variables defined in sighand.c. */
|
|
|
|
extern USHORT FAR CtrlCFlag; /* Used by sig handler for Ctrl-C event. */
|
|
|
|
VOID NEAR
|
|
_sendmsg ( int, int, TCHAR FAR *, TCHAR FAR *, DWORD, DWORD);
|
|
|
|
|
|
|
|
/*
|
|
* NOTE! be CAREFUL when adding stuff here, make sure what's appropriate
|
|
* is put in the DOS NameMsgList as well.
|
|
*/
|
|
|
|
#define NAME_MSG_NAME 0
|
|
#define NAME_MSG_FWD ( NAME_MSG_NAME + 1)
|
|
#define NAME_MSG_FWD_FROM ( NAME_MSG_FWD + 1 )
|
|
static MESSAGE NameMsgList[] = {
|
|
{ APE2_NAME_MSG_NAME, NULL },
|
|
{ APE2_NAME_MSG_FWD, NULL },
|
|
{ APE2_NAME_MSG_FWD_FROM, NULL },
|
|
};
|
|
|
|
#define NUM_NAME_MSGS (sizeof(NameMsgList)/sizeof(NameMsgList[0]))
|
|
|
|
/***
|
|
* name_display()
|
|
* Display messaging names
|
|
*
|
|
* Args:
|
|
* none
|
|
*
|
|
* Returns:
|
|
* 0 - success
|
|
* exit 2 - command failed
|
|
*/
|
|
VOID name_display(VOID)
|
|
{
|
|
DWORD dwErr; /* API return status */
|
|
DWORD num_read; /* num entries read by API */
|
|
DWORD cTotalAvail;
|
|
DWORD maxLen; /* max message len */
|
|
DWORD i;
|
|
LPMSG_INFO_1 msg_entry;
|
|
LPMSG_INFO_1 msg_entry_buffer;
|
|
static TCHAR fmt1[] = TEXT("%-15.15Fws ");
|
|
|
|
start_autostart(txt_SERVICE_REDIR);
|
|
start_autostart(txt_SERVICE_MSG_SRV);
|
|
|
|
if (dwErr = NetMessageNameEnum(
|
|
NULL,
|
|
1,
|
|
(LPBYTE*)&msg_entry_buffer,
|
|
MAX_PREFERRED_LENGTH,
|
|
&num_read,
|
|
&cTotalAvail,
|
|
NULL))
|
|
ErrorExit(dwErr);
|
|
|
|
if (num_read == 0)
|
|
EmptyExit();
|
|
|
|
GetMessageList(NUM_NAME_MSGS, NameMsgList, &maxLen);
|
|
|
|
PrintNL();
|
|
WriteToCon(fmt1, (TCHAR FAR *) NameMsgList[NAME_MSG_NAME].msg_text);
|
|
PrintNL();
|
|
PrintLine();
|
|
|
|
msg_entry = msg_entry_buffer ;
|
|
for (i = 0; i < num_read; i++)
|
|
{
|
|
WriteToCon(fmt1, msg_entry->msgi1_name);
|
|
PrintNL();
|
|
msg_entry += 1;
|
|
}
|
|
|
|
NetApiBufferFree((TCHAR FAR *) msg_entry_buffer);
|
|
InfoSuccess();
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
* name_add()
|
|
* Add a messaging name
|
|
*
|
|
* Args:
|
|
* name - name to add
|
|
*
|
|
* Returns:
|
|
* 0 - success
|
|
* exit(2) - command failed
|
|
*/
|
|
VOID name_add(TCHAR * name)
|
|
{
|
|
USHORT err; /* function return status */
|
|
DWORD dwErr;
|
|
|
|
start_autostart(txt_SERVICE_REDIR);
|
|
start_autostart(txt_SERVICE_MSG_SRV);
|
|
|
|
if (err = LUI_CanonMessagename( name ) )
|
|
ErrorExit(err);
|
|
|
|
if (dwErr = NetMessageNameAdd(NULL, name))
|
|
ErrorExit(dwErr);
|
|
|
|
InfoPrintInsTxt(APE_NameSuccess, name);
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
* name_del()
|
|
* Delete a messaging name
|
|
*
|
|
* Args:
|
|
* name - name to delete
|
|
*
|
|
* Returns:
|
|
* 0 - success
|
|
* exit(2) - command failed
|
|
*/
|
|
VOID name_del(TCHAR * name)
|
|
{
|
|
USHORT err; /* function return status */
|
|
DWORD dwErr;
|
|
|
|
start_autostart(txt_SERVICE_REDIR);
|
|
start_autostart(txt_SERVICE_MSG_SRV);
|
|
|
|
if (err = LUI_CanonMessagename( name ) )
|
|
ErrorExit(err);
|
|
|
|
dwErr = NetMessageNameDel(NULL, name);
|
|
|
|
switch(dwErr) {
|
|
case NERR_DeleteLater:
|
|
InfoPrint(err);
|
|
InfoSuccess();
|
|
break;
|
|
case 0:
|
|
InfoPrintInsTxt(APE_DelSuccess, name);
|
|
break;
|
|
default:
|
|
ErrorExit(dwErr);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***
|
|
* send_direct()
|
|
* Send a directed message to a user
|
|
*
|
|
* Args:
|
|
* recipient - recipient of msg
|
|
*
|
|
* Returns:
|
|
* 0 - success
|
|
* exit(1) - command completed with errors
|
|
* exit(2) - command failed
|
|
*
|
|
* Operation:
|
|
* Performs a send to the messaging name.
|
|
*
|
|
* Note:
|
|
*/
|
|
VOID send_direct ( TCHAR * recipient )
|
|
{
|
|
|
|
start_autostart(txt_SERVICE_REDIR);
|
|
|
|
if (_tcscmp(recipient,TEXT("*")) == 0)
|
|
{
|
|
send_domain(0);
|
|
return;
|
|
}
|
|
|
|
_sendmsg ( 2,
|
|
TO_NAME,
|
|
recipient,
|
|
recipient,
|
|
1,
|
|
0 );
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
* send_users()
|
|
* Send a message to all users on a server
|
|
*
|
|
* Args:
|
|
* none
|
|
*
|
|
* Returns:
|
|
* 0 - success
|
|
* exit(1) - command completed with errors
|
|
* exit(2) - command failed
|
|
*/
|
|
|
|
VOID
|
|
send_users(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD dwErr; /* API return status */
|
|
DWORD cTotalAvail;
|
|
LPTSTR pBuffer;
|
|
DWORD num_read; /* num entries read by API */
|
|
|
|
start_autostart(txt_SERVICE_REDIR);
|
|
|
|
/* Who gets the message? */
|
|
|
|
/* possible race cond... tough */
|
|
if (dwErr = NetSessionEnum(
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
(LPBYTE*)&pBuffer,
|
|
MAX_PREFERRED_LENGTH,
|
|
&num_read,
|
|
&cTotalAvail,
|
|
NULL))
|
|
{
|
|
ErrorExit(dwErr);
|
|
}
|
|
|
|
if (num_read == 0)
|
|
{
|
|
InfoPrint(APE_NoUsersOfSrv);
|
|
NetcmdExit(0);
|
|
}
|
|
|
|
_sendmsg(1,
|
|
TO_USERS,
|
|
NULL,
|
|
pBuffer,
|
|
num_read,
|
|
sizeof(SESSION_INFO_0));
|
|
|
|
NetApiBufferFree(pBuffer);
|
|
|
|
}
|
|
|
|
|
|
/***
|
|
* send_domain()
|
|
* Send a message to all users on a server
|
|
*
|
|
* Args:
|
|
* is_switch - true if /DOMAIN switch on command line
|
|
*
|
|
* Returns:
|
|
* 0 - success
|
|
* exit(1) - command completed with errors
|
|
* exit(2) - command failed
|
|
*/
|
|
|
|
VOID
|
|
send_domain(
|
|
int is_switch
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
LPWKSTA_INFO_10 wi10_p;
|
|
TCHAR domain_buf[MAX_PATH+2];
|
|
int i, have_name = 0;
|
|
LPTSTR ptr;
|
|
|
|
start_autostart(txt_SERVICE_REDIR);
|
|
|
|
/* If there was a /DOMAIN switch, find it and get the domain
|
|
* name. A /DOMAIN switch w/o a domain is taken as meaning
|
|
* "primary domain". We just skip on by in this case.
|
|
*/
|
|
|
|
if (is_switch)
|
|
{
|
|
for (i=0; SwitchList[i]; i++)
|
|
{
|
|
/* If we match /DOMAIN exactly, there is no argument, so
|
|
* we skip this case (and do NOT set have_name).
|
|
*/
|
|
|
|
if (!_tcscmp(SwitchList[i], swtxt_SW_DOMAIN))
|
|
continue;
|
|
|
|
/* OK, so we know the swith is not just plain /DOMAIN.
|
|
* All other switches MUST have a colon. Just so happens
|
|
* that the only other legal switch is /DOMAIN:foo.
|
|
*/
|
|
|
|
if ((ptr = FindColon(SwitchList[i])) == NULL)
|
|
ErrorExit(APE_InvalidSwitchArg);
|
|
|
|
/* See if this is indeed /DOMAIN:foo. If so, process it.
|
|
* SPECIAL CASE ... if the "argument" is the null string,
|
|
* we pretend we never got the name, just as for /DOMAIN
|
|
* (without the colon).
|
|
*/
|
|
|
|
if ( !(_tcscmp(SwitchList[i], swtxt_SW_DOMAIN)) )
|
|
{
|
|
if (_tcslen(ptr) > 0)
|
|
{
|
|
if( _tcslen(ptr) > DIMENSION(domain_buf)-2 )
|
|
ErrorExit(APE_InvalidSwitchArg);
|
|
_tcsncpy(domain_buf,ptr,DIMENSION(domain_buf)-2);
|
|
domain_buf[DIMENSION(domain_buf)-2] = 0;
|
|
have_name = 1;
|
|
}
|
|
}
|
|
else
|
|
ErrorExit(APE_InvalidSwitchArg);
|
|
}
|
|
}
|
|
|
|
/* If we do not have a domain name yet, because:
|
|
* (a) no /DOMAIN switch was given, or
|
|
* (b) the /DOMAIN switch had no argument,
|
|
* then fetch the primary domain name.
|
|
*/
|
|
|
|
if (! have_name)
|
|
{
|
|
/* possible race cond... tough */
|
|
if (dwErr = MNetWkstaGetInfo (10, (LPBYTE*) &wi10_p))
|
|
{
|
|
ErrorExit(dwErr);
|
|
}
|
|
|
|
_tcsncpy(domain_buf, wi10_p->wki10_langroup, DIMENSION(domain_buf)-2);
|
|
domain_buf[DIMENSION(domain_buf)-2] = 0;
|
|
}
|
|
|
|
/* Add the tag "*" to the name, then send the message. Note that
|
|
* the first arg depends on whether we got to this function
|
|
* via the /DOMAIN method (is_switch) or ASTERISK. If the latter,
|
|
* we start at ArgList[2] to skip the ASTERISK.
|
|
*/
|
|
|
|
_tcscat(domain_buf,TEXT("*"));
|
|
|
|
_sendmsg ( (is_switch ? 1 : 2),
|
|
TO_DOMAIN,
|
|
domain_buf,
|
|
domain_buf,
|
|
1,
|
|
0 );
|
|
|
|
NetApiBufferFree((TCHAR FAR *) wi10_p);
|
|
|
|
}
|
|
|
|
|
|
/***
|
|
* send_broadcast()
|
|
* Send a message to all users on the net
|
|
*
|
|
* Args:
|
|
* is_switch - true if /BROADCAST switch on command line
|
|
*
|
|
* Returns:
|
|
* 0 - success
|
|
* exit(1) - command completed with errors
|
|
* exit(2) - command failed
|
|
*/
|
|
|
|
VOID send_broadcast ( int is_switch )
|
|
{
|
|
|
|
start_autostart(txt_SERVICE_REDIR);
|
|
|
|
/* The first arg depends on whether we got to this function
|
|
* via the /BROADCAST method (is_switch) or ASTERISK. If the latter,
|
|
* we start at ArgList[2] to skip the ASTERISK.
|
|
*
|
|
* Note that in the current spec, NET SEND * is a true broadcast
|
|
* (and thus comes into this function) only in DOS.
|
|
*/
|
|
|
|
_sendmsg ( (is_switch ? 1 : 2),
|
|
TO_ALL,
|
|
NULL,
|
|
TEXT("*"),
|
|
1,
|
|
0 );
|
|
}
|
|
|
|
#define MSGBUF 1024
|
|
|
|
VOID NEAR _sendmsg ( int firstarg, int dest, TCHAR FAR * v_dest,
|
|
TCHAR FAR * t_list, DWORD t_num, DWORD t_size )
|
|
{
|
|
DWORD err;
|
|
LPTSTR message_buffer ;
|
|
int a_index, msglen, buflen = MSGBUF;
|
|
DWORD t_index;
|
|
int src;
|
|
LPTSTR tf_recipient;
|
|
DWORD last_err;
|
|
DWORD err_cnt = 0;
|
|
LPTSTR tmpptr;
|
|
|
|
a_index = firstarg;
|
|
|
|
if ( !(message_buffer = malloc(buflen*sizeof(TCHAR))) )
|
|
ErrorExit(ERROR_NOT_ENOUGH_MEMORY) ;
|
|
|
|
if (ArgList[a_index])
|
|
{
|
|
src = FROM_CMD_LINE;
|
|
msglen = 0 ;
|
|
|
|
/*
|
|
* copy msg text into buf.
|
|
* msglen is length currently in buffer, not including null terminator
|
|
* needed is length of next arg, not including null terminator
|
|
*/
|
|
*message_buffer = NULLC;
|
|
do
|
|
{
|
|
int needed = _tcslen(ArgList[a_index]) ;
|
|
|
|
if ((msglen+needed) > (int)(buflen-2)) // 2 not 1 because " " is appended
|
|
{
|
|
LPWSTR lpTemp;
|
|
|
|
//
|
|
// Reallocate the buffer as needed. Add extra in hopes
|
|
// that we won't need to reallocate again as a result.
|
|
//
|
|
|
|
buflen = (msglen + needed) * 2;
|
|
|
|
lpTemp = realloc(message_buffer, buflen * sizeof(WCHAR));
|
|
|
|
if (!lpTemp)
|
|
{
|
|
ErrorExit(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
message_buffer = lpTemp;
|
|
}
|
|
|
|
_tcscat(message_buffer, ArgList[a_index]);
|
|
msglen += needed+1 ;
|
|
_tcscat(message_buffer, TEXT(" "));
|
|
|
|
} while(ArgList[++a_index]);
|
|
|
|
/* delete trailing TEXT(" ") */
|
|
message_buffer[_tcslen(message_buffer) - 1] = NULLC;
|
|
}
|
|
else
|
|
{
|
|
free(message_buffer) ;
|
|
ErrorExit(APE_SendFileNotSupported);
|
|
}
|
|
|
|
/* send 'da msg */
|
|
|
|
for (t_index = 0; t_index < t_num; t_index++)
|
|
{
|
|
switch(dest)
|
|
{
|
|
case TO_NAME:
|
|
case TO_DOMAIN:
|
|
case TO_ALL:
|
|
tf_recipient = (TCHAR FAR *) t_list;
|
|
break;
|
|
|
|
case TO_USERS:
|
|
tf_recipient = *((TCHAR FAR * FAR *)t_list);
|
|
break;
|
|
}
|
|
|
|
err = 0;
|
|
if( (err = LUI_CanonMessageDest( tf_recipient )) == 0 )
|
|
{
|
|
err = NetMessageBufferSend(NULL,
|
|
tf_recipient,
|
|
NULL,
|
|
(LPBYTE) message_buffer,
|
|
_tcslen(message_buffer)*sizeof(TCHAR));
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
last_err = err;
|
|
err_cnt++;
|
|
InfoPrintInsTxt(APE_SendErrSending, tf_recipient);
|
|
}
|
|
|
|
// must cast t_list since t_size is the size in bytes, but t_list
|
|
// is a TCHAR *.
|
|
(BYTE *) t_list += t_size;
|
|
}
|
|
|
|
free(message_buffer) ;
|
|
message_buffer = NULL ;
|
|
|
|
/* Bye, bye */
|
|
|
|
if (err_cnt == t_num && err_cnt > 0)
|
|
{
|
|
ErrorExit(last_err);
|
|
}
|
|
else if (err_cnt)
|
|
{
|
|
InfoPrint(APE_CmdComplWErrors);
|
|
NetcmdExit(1);
|
|
}
|
|
|
|
IStrings[0] = v_dest;
|
|
|
|
switch(dest)
|
|
{
|
|
case TO_NAME:
|
|
InfoPrintIns(APE_SendSuccess, 1);
|
|
break;
|
|
|
|
case TO_USERS:
|
|
InfoPrint(APE_SendUsersSuccess);
|
|
break;
|
|
|
|
case TO_DOMAIN:
|
|
/*
|
|
* Strip off the trailing ASTERISK.
|
|
*/
|
|
tmpptr = _tcschr( IStrings[0], ASTERISK );
|
|
if (tmpptr != NULL)
|
|
*tmpptr = NULLC;
|
|
InfoPrintIns(APE_SendDomainSuccess, 1);
|
|
break;
|
|
|
|
case TO_ALL:
|
|
InfoPrint(APE_SendAllSuccess);
|
|
break;
|
|
}
|
|
}
|
|
|