mars_dosutils-0.10

This commit is contained in:
Mario Fetka 2011-11-13 00:40:40 +01:00
parent 5e6805dd31
commit 975f34431a
18 changed files with 768 additions and 529 deletions

80
capture.c Normal file
View File

@ -0,0 +1,80 @@
/* capture.c 05-Apr-96 */
/****************************************************************
* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany *
****************************************************************/
#include "net.h"
static int usage(void)
{
fprintf(stderr, "usage:\t%s level\n", funcname);
fprintf(stderr, "\tlevel=0 .. 99\n" );
return(-1);
}
static int parse_argv(uint8 *devname, uint8 *queuename,
int argc, char *argv[], int parsemode)
{
int k = 0;
*devname = '\0';
*queuename = '\0';
while (++k < argc) {
uint8 *p = argv[k];
if (k == 1) {
strmaxcpy(devname, p, 20);
upstr(devname);
if (!strcmp(devname, "PRN"))
strcpy(devname, "LPT1");
} else if (k == 2) {
strmaxcpy(queuename, p, 20);
upstr(queuename);
}
}
return(0);
}
static int do_capture(uint8 *drvstr, uint8 *queuestr, int delete)
{
int result = redir_device_drive(delete ? -1 : 0x3, drvstr, queuestr);
return(result);
}
static int show_capture(uint8 *drvstr)
{
int result;
int k =-1;
uint8 devname[20];
uint8 remotename[130];
int devicetyp;
while ((result = list_redir(++k, &devicetyp, devname, remotename)) > -1){
if (result > -1 && devicetyp == 0x3) {
upstr(devname);
upstr(remotename);
if (!drvstr || !*drvstr || !strcmp(devname, drvstr))
fprintf(stdout, "%-10s captured to %s\n", devname, remotename);
}
}
return(result);
}
int func_capture(int argc, char *argv[], int mode)
{
uint8 devname [22];
uint8 queuestr[22];
if (!parse_argv(devname, queuestr, argc, argv, mode)) {
int result=0;
if (*queuestr || mode == 1) {
result=do_capture(devname, queuestr, mode);
if (result< 0)
fprintf(stderr, "capture error:%d, device:%s \n", result, devname);
}
if (mode != 1)
show_capture(devname);
else if (result > -1)
fprintf(stdout, "Capture of %s removed\n", devname);
return(result);
}
return(1);
}

87
doc
View File

@ -1,46 +1,93 @@
/* DOC for NET.EXE */
/* last updated: 21-May-96 */
This is a short description of net.exe which is a simple DOS-client
programm to allow standard NCP network actions, mainly for mars_nwe.
All functions are called as a second parameter.
This programm is very incomplete till now, but some functions
program to allow standard NCP network actions, mainly for mars_nwe.
All functions are called as a second parameter, or if the program
is renamed to a guilty function like login.exe then the function
will be the progname. This is very usefull for login.exe.
This program is very incomplete till now, but some functions
works well with mars_nwe.
LOGOUT:
Logout from a NCP Server.
LOGIN:
usage: LOGIN [-u] [user | user password]
-u = use unencrypted password.
With this function you can log into a NCP Server.
Its only make a login, no mappings or something else.
If there exists a 'login' file in the same directory as
net.exe resides then this file will be interpreted as a
command file. You also can use command files with
the PROFILE command.
It is usefull to copy (or do a Linux link) net.exe to login.exe.
If you want a login similar to NOVELL's login.exe you should
do it with a batch job.
example for a 'login' script (resides in same directory as net.exe)
map f:=SYS:
map h:=home:
map z:=SYS:PUBLIC
path s16:=z:.
capture lpt1 q1
profile h:\profile # will call users home 'profile'
example:
[\LOGIN\LOGIN.BAT]
@echo OFF
net logout
net login %1 %2 %3
if errorlevel 1 goto :end
map h:=HOME:
if not exist h:\profile.bat goto :end
h:
profile.bat
:end
PROFILE:
usage: PROFILE filename
With this function you are able to run a command script.
In this command script you can use every net.exe command.
SPAWN:
With SPAWN you can start external programs.
PASSWD:
usage: PASSWD [user]
With this function you are able to change a users password.
This call uses the old unencryted change password call !!
PATH:
usage: PATH sn:[=[path]]
sn = 's1' .. 's16'
With this function a new path element can be created.
Its only sets the path environment.
Its only sets the path environment !
PATHINS:
usage: PATHINS sn:[=[path]]
sn = 's1' .. 's16'
like PATH, but inserts PATH, not overwrites.
PATHDEL:
usage: PATHDEL sn:
sn = 's1' .. 's16'
deletes PATH element
MAP:
usage: MAP [d:[=[path]]]
d = 'A' .. 'Z'
Maps a drive to a volume or volume/path.
MAPDEL:
usage: MAPDEL d:
d = 'A' .. 'Z'
Removes a map.
LOGOUT:
Logout from a NCP Server.
DEBUG:
For setting debug flag in mars_nwe processes.
If you want to use this, you must set
mars_nwe/config.h: FUNC_17_02_IS_DEBUG to '1'
SPAWN:
EXEC:
external program execution spawning or overlayed.

BIN
e.pck

Binary file not shown.

317
kern.lst
View File

@ -1,317 +0,0 @@
Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 1
kern.asm
1 ; kern.asm: 20-Nov-93, 21:52
2 IDEAL
3 P286
4 0000 MODEL LARGE
5 ; Fuer Turboc gerettet werden muessen folgende Register:
6 ; BP, SS, SP, DS, CS u. SI, DI
7
8 MACRO P_START
9 push bp
10 mov bp, sp
11 ENDM
12
13 MACRO P_END
14 pop bp
15 ENDM
16
17 MACRO PUSH_REGS
18 push ds
19 push si
20 push di
21 ENDM
22
23 MACRO POP_REGS
24 pop di
25 pop si
26 pop ds
27 ENDM
28
29 ;; EXTRN _esr_routine:FAR
30
31 PUBLIC _IPXinit;
32 PUBLIC _IPXopen_socket;
33 PUBLIC _IPXclose_socket;
34 PUBLIC _IPXlisten;
35 ;; PUBLIC _asm_esr_routine;
36 PUBLIC _xmemmove;
37 PUBLIC _Net_Call;
38
39 0000 DATASEG
40 0000 0000FFFE enterIPX DD FAR
41
42 0004 CODESEG
43 0000 PROC _IPXinit;
44 P_START
1 45 0000 55 push bp
1 46 0001 8B EC mov bp, sp
47 PUSH_REGS
1 48 0003 1E push ds
1 49 0004 56 push si
1 50 0005 57 push di
51 0006 B8 7A00 mov ax, 7A00h
52 0009 CD 2F int 2Fh
53 000B 3C FF cmp al, 0FFh
54 000D 75 10 jne @@fertig
55 000F B9 0000s mov cx, @data
56 0012 8E D9 mov ds, cx
57 0014 89 3E 0000r mov [WORD PTR enterIPX], di
Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 2
kern.asm
58 0018 8C C0 mov ax, es
59 001A A3 0002r mov [WORD PTR enterIPX+2], ax
60 001D B0 01 mov al, 1 ; OK
61 001F @@fertig:
62 001F B4 00 mov ah, 0
63 POP_REGS
1 64 0021 5F pop di
1 65 0022 5E pop si
1 66 0023 1F pop ds
67 P_END
1 68 0024 5D pop bp
69 0025 CB ret ; OK = 1 ; nicht ok = 0
70 0026 ENDP
71
72 0026 PROC _xmemmove;
73 ARG z:DATAPTR, q:DATAPTR, nmbr:WORD; Argumente
74 0026 FA cli ; Disable Interrupts
75 0027 55 push bp
76 0028 8B EC mov bp,sp
77 002A 8B 4E 0E mov cx, [nmbr];
78 002D 0B C9 or cx, cx;
79 002F 74 1F jz @@fertig; Anzahl ist 0;
80 0031 1E push ds;
81 0032 56 push si;
82 0033 57 push di;
83 0034 9C pushf
84 0035 C5 76 0A lds si, [q] ; Quelle
85 0038 C4 7E 06 les di, [z] ; Ziel
86 003B 3B FE cmp di, si ;
87 003D 7C 0A jl @@L1 ; Ziel ist kleiner
88 003F FD std ; Richtungsflag setzen
89 0040 49 dec cx
90 0041 03 F9 add di, cx ; Von oben nach unten kopieren
91 0043 03 F1 add si, cx ;
92 0045 41 inc cx ; alten Wert wiederherstellen
93 0046 EB 02 90 jmp @@L2;
94 0049 @@L1:
95 0049 FC cld ; Richtungsflag loeschen
96 004A @@L2: ; und nun das eigentliche kopieren
97 004A F3> A4 REP movsb ;
98 004C 9D popf
99 004D 5F pop di;
100 004E 5E pop si;
101 004F 1F pop ds;
102 0050 @@fertig:
103 0050 5D pop bp;
104 0051 FB sti ; enable Interrupts
105 0052 CB ret
106 0053 ENDP
107
108 0053 PROC _IPXopen_socket;
109 ARG sock:WORD, live:WORD
110 P_START
1 111 0053 55 push bp
1 112 0054 8B EC mov bp, sp
113 PUSH_REGS
1 114 0056 1E push ds
Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 3
kern.asm
1 115 0057 56 push si
1 116 0058 57 push di
117 0059 8B 46 08 mov ax, [live]
118 005C 8B 56 06 mov dx, [sock]
119 005F BB 0000s mov bx, @data
120 0062 8E DB mov ds, bx
121 0064 BB 0000 mov bx, 0
122 0067 FF 1E 0000r call [enterIPX]
123 006B 3C FF cmp al, 0FFh
124 006D 75 06 jne @@L1
125 006F B8 FFFF mov ax, -1 ; Socket already open
126 0072 EB 0D 90 jmp @@L3
127 0075 @@L1:
128 0075 3C FE cmp al, 0FEh
129 0077 75 06 jne @@L2
130 0079 B8 FFFE mov ax, -2 ; Socket Table full
131 007C EB 03 90 jmp @@L3
132 007F @@L2:
133 007F 8B C2 mov ax, dx
134 0081 @@L3:
135 POP_REGS
1 136 0081 5F pop di
1 137 0082 5E pop si
1 138 0083 1F pop ds
139 P_END
1 140 0084 5D pop bp
141 0085 CB ret
142 0086 ENDP
143
144 0086 PROC _IPXclose_socket;
145 ARG sock:WORD
146 P_START
1 147 0086 55 push bp
1 148 0087 8B EC mov bp, sp
149 PUSH_REGS
1 150 0089 1E push ds
1 151 008A 56 push si
1 152 008B 57 push di
153 008C 8B 56 06 mov dx, [sock]
154 008F BB 0000s mov bx, @data
155 0092 8E DB mov ds, bx
156 0094 BB 0001 mov bx, 1
157 0097 FF 1E 0000r call [enterIPX]
158 POP_REGS
1 159 009B 5F pop di
1 160 009C 5E pop si
1 161 009D 1F pop ds
162 P_END
1 163 009E 5D pop bp
164 009F CB ret
165 00A0 ENDP
166
167 00A0 PROC _IPXlisten;
168 ARG ecb:DATAPTR
169 P_START
1 170 00A0 55 push bp
1 171 00A1 8B EC mov bp, sp
Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 4
kern.asm
172 PUSH_REGS
1 173 00A3 1E push ds
1 174 00A4 56 push si
1 175 00A5 57 push di
176 00A6 C4 76 06 les si, [ecb] ; Adresse ecb
177 00A9 BB 0000s mov bx, @data
178 00AC 8E DB mov ds, bx
179 00AE BB 0004 mov bx, 4
180 00B1 FF 1E 0000r call [enterIPX]
181 POP_REGS
1 182 00B5 5F pop di
1 183 00B6 5E pop si
1 184 00B7 1F pop ds
185 P_END
1 186 00B8 5D pop bp
187 00B9 B4 00 mov ah, 0
188 00BB CB ret
189 00BC ENDP
190
191 ;; PROC _asm_esr_routine;
192 ;; push bp;
193 ;; PUSH_REGS;
194 ;; mov ax, @data
195 ;; mov ds, ax ; F<>r C PROGRAMM
196 ;; push es; Adressegment vom EBC
197 ;; push si; Adressoffset vom ECB
198 ;; call _esr_routine; C ROUTINE
199 ;; pop si;
200 ;; pop es;
201 ;; POP_REGS;
202 ;; pop bp;
203 ;; cli ; no Interrupt says NOVELL
204 ;; ret
205 ;; ENDP
206
207
208 00BC PROC _Net_Call;
209 ARG func:WORD, req:DATAPTR, repl:DATAPTR; Argumente
210 00BC 55 push bp
211 00BD 8B EC mov bp, sp
212 00BF 8B 46 06 mov ax, [func];
213 00C2 1E push ds;
214 00C3 56 push si;
215 00C4 57 push di;
216 00C5 9C pushf
217 00C6 C5 76 08 lds si, [req] ; Request
218 00C9 C4 7E 0C les di, [repl] ; Reply
219 00CC CD 21 int 21h
220 00CE 9D popf
221 00CF 5F pop di;
222 00D0 5E pop si;
223 00D1 1F pop ds;
224 00D2 5D pop bp;
225 00D3 B4 00 mov ah, 0
226 00D5 CB ret
227 00D6 ENDP
228
Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 5
kern.asm
229 END
Turbo Assembler Version 3.1 28/04/96 13:28:50 Page 6
Symbol Table
Symbol Name Type Value
??DATE Text "28/04/96"
??FILENAME Text "kern "
??TIME Text "13:28:50"
??VERSION Number 030A
@32BIT Text 0
@@FERTIG Near KERN_TEXT:001F
@@FERTIG Near KERN_TEXT:0050
@@L1 Near KERN_TEXT:0049
@@L1 Near KERN_TEXT:0075
@@L2 Near KERN_TEXT:004A
@@L2 Near KERN_TEXT:007F
@@L3 Near KERN_TEXT:0081
@CODE Text KERN_TEXT
@CODESIZE Text 1
@CPU Text 0787H
@CURSEG Text KERN_TEXT
@DATA Text DGROUP
@DATASIZE Text 1
@FILENAME Text KERN
@INTERFACE Text 00H
@MODEL Text 5
@STACK Text DGROUP
@WORDSIZE Text 2
ECB Number [DGROUP:BP+0006]
ENTERIPX Dword DGROUP:0000
FUNC Number [DGROUP:BP+0006]
LIVE Number [DGROUP:BP+0008]
NMBR Number [DGROUP:BP+000E]
Q Number [DGROUP:BP+000A]
REPL Number [DGROUP:BP+000C]
REQ Number [DGROUP:BP+0008]
SOCK Number [DGROUP:BP+0006]
Z Number [DGROUP:BP+0006]
_IPXCLOSE_SOCKET + Far KERN_TEXT:0086
(_IPXclose_socket)
_IPXINIT (_IPXinit) Far KERN_TEXT:0000
_IPXLISTEN (_IPXlisten) Far KERN_TEXT:00A0
_IPXOPEN_SOCKET + Far KERN_TEXT:0053
(_IPXopen_socket)
_NET_CALL (_Net_Call) Far KERN_TEXT:00BC
_XMEMMOVE (_xmemmove) Far KERN_TEXT:0026
Macro Name
POP_REGS
PUSH_REGS
P_END
P_START
Groups & Segments Bit Size Align Combine Class
DGROUP Group
_DATA 16 0004 Word Public DATA
KERN_TEXT 16 00D6 Word Public CODE

View File

@ -1,4 +0,0 @@
c:\net logout
c:\net login %1 %2 %3
map h:=HOME:

215
login.c
View File

@ -1,4 +1,4 @@
/* login.c 05-Apr-96 */
/* login.c 21-May-96 */
/****************************************************************
* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany *
@ -7,7 +7,6 @@
#include "net.h"
#include "nwcrypt.h"
static int do_change_object_passwd(char *name,
uint16 objtyp,
char *oldpassword,
@ -115,12 +114,13 @@ static int login_usage(void)
return(-1);
}
int func_login(int argc, char *argv[])
int func_login(int argc, char *argv[], int mode)
{
int result=-1;
int option=0;
uint8 uname[200];
uint8 upasswd[200];
SEARCH_VECTOR save_drives;
if (argc > 1) {
if (argv[1][0] == '-') {
@ -130,13 +130,15 @@ int func_login(int argc, char *argv[])
argv++;
}
}
get_search_drive_vektor(save_drives);
remove_nwpathes();
if (argc > 1) strmaxcpy(uname, argv[1], sizeof(uname) -1);
else uname[0]='\0';
if (argc > 2) strmaxcpy(upasswd, argv[2], sizeof(upasswd) -1);
else upasswd[0]='\0';
while (result) {
if (!uname[0]) getstr("login", uname, sizeof(uname)-1, 1);
if (!uname[0]) getstr("Login", uname, sizeof(uname)-1, 1);
if (uname[0]) {
upstr(uname);
upstr(upasswd);
@ -152,16 +154,29 @@ int func_login(int argc, char *argv[])
}
} else break;
}
if (result > -1) {
char profile[200];
remove_nwpathes();
sprintf(profile, "%slogin", prgpath);
read_command_file(profile);
} else {
(void)set_search_drive_vektor(save_drives);
}
return(result);
}
int func_logout(int argc, char *argv[])
int func_logout(int argc, char *argv[], int mode)
{
if (logout()) fprintf(stderr, "logout=%d", neterrno);
remove_nwpathes();
if (logout()) {
fprintf(stderr, "logout=%d\n", neterrno);
return(1);
}
return(0);
}
int func_passwd(int argc, char *argv[])
int func_passwd(int argc, char *argv[], int mode)
{
int result=0;
uint8 uname[100];
@ -169,7 +184,7 @@ int func_passwd(int argc, char *argv[])
uint32 my_obj_id;
if (ncp_14_46(&my_obj_id) < 0 || my_obj_id == MAX_U32 || !my_obj_id) {
fprintf(stderr, "Cannot get actual User ID\n");
fprintf(stderr, "Cannot get actual user id\n");
result = -1;
}
@ -179,13 +194,13 @@ int func_passwd(int argc, char *argv[])
upstr(uname);
obj_id = ncp_17_35(uname, 1);
if (!obj_id) {
fprintf(stderr, "Unkwown User: %s\n", uname);
fprintf(stderr, "Unkwown user: %s\n", uname);
return(-1);
}
} else if (!result) {
uint16 obj_typ;
if (ncp_17_36(my_obj_id, uname, &obj_typ) || obj_typ != 1) {
fprintf(stderr, "Cannot get actual Username\n");
fprintf(stderr, "Cannot get actual username\n");
result=-1;
}
}
@ -194,11 +209,11 @@ int func_passwd(int argc, char *argv[])
uint8 newpasswd2[130];
if (my_obj_id == 1L) *upasswd='\0';
else {
getstr("Old Password", upasswd, sizeof(upasswd)-1, 0);
getstr("Old password", upasswd, sizeof(upasswd)-1, 0);
upstr(upasswd);
}
getstr("New Password", newpasswd, sizeof(newpasswd)-1, 0);
getstr("New Password again", newpasswd2, sizeof(newpasswd2)-1, 0);
getstr("New password", newpasswd, sizeof(newpasswd)-1, 0);
getstr("New password again", newpasswd2, sizeof(newpasswd2)-1, 0);
if (!strcmp(newpasswd, newpasswd2)) {
upstr(uname);
upstr(newpasswd);
@ -213,3 +228,175 @@ int func_passwd(int argc, char *argv[])
return(result);
}
static int get_line(FILE *f, char *buff, int bufsize, uint8 *str, int strsize)
/* returns command line or -1 if ends */
{
if ((FILE*) NULL != f) {
while (fgets(buff, bufsize, f) != NULL){
char *p = buff;
char *beg = NULL;
char c;
int len=0;
while (0 != (c = *p++) && c != '\n' && c != '\r' && c != '#') {
if (!beg){
if (c != '\t' && c != 32) {
beg = p - 1;
len = 1;
}
} else ++len;
}
if (len) {
strmaxcpy((uint8*)str, (uint8*)beg, min(len, strsize-1));
return(0);
}
}
}
return(-1);
}
static char **build_argv(char *buf, int bufsize, char *command)
/* routine returns **argv for use with execv routines */
/* buf will contain the path component */
{
int len = strlen(command);
int offset = ((len+4) / 4) * 4; /* aligned offset for **argv */
int components = (bufsize - offset) / 4;
if (components > 1) { /* minimal argv[0] + NULL */
char **argv = (char **)(buf+offset);
char **pp = argv;
char *p = buf;
char c;
int i=0;
--components;
memcpy(buf, command, len);
memset(buf+len, 0, bufsize - len);
*pp = p;
while ((0 != (c = *p++)) && i < components) {
if (c == 32 || c == '\t') {
*(p-1) = '\0';
if (*p != 32 && *p != '\t') {
*(++pp)=p;
i++;
}
} else if (!i && c == '/') { /* here i must get argv[0] */
*pp=p;
}
}
return(argv);
}
return(NULL);
}
int read_command_file(char *fstr)
{
FILE *f=fopen(fstr, "r");
int result=-1;
if (f != NULL) {
char *linebuf= xmalloc(512);
char *buf = xmalloc(512);
while (get_line(f, buf, 512, linebuf, 512) > -1) {
char **argv=build_argv(buf, 512, linebuf);
if (argv != NULL) {
int argc=0;
char **pp=argv;
while (*pp) {
argc++;
pp++;
}
upstr(argv[0]);
if (argc > 2 && !strcmp(argv[0], "ECHO")) {
char *p=argv[argc-1];
while (p-- > argv[1]) {
if (*p=='\0') *p=32;
}
argc=2;
}
call_func_entry(argc, argv);
result = 0;
}
}
fclose(f);
xfree(linebuf);
xfree(buf);
} else result=-2;
return(result);
}
int func_profile(int argc, char *argv[], int mode)
{
if (argc < 2) {
fprintf(stderr, "usage:\t%s fn\n", funcname);
return(-1);
}
if (read_command_file(argv[1]) == -2) {
fprintf(stderr, "command file %s not found\n", argv[1]);
}
return(0);
}
int func_cwd(int argc, char *argv[], int mode)
{
char pathname[65];
int len;
if (argc < 2) {
fprintf(stderr, "usage:\t%s path\n", funcname);
return(-1);
}
strmaxcpy(pathname, argv[1], sizeof(pathname) -1);
korrpath(pathname);
if (0 != (len = strlen(pathname))) {
char *p=pathname+len-1;
if (*p == '/' || *p == ':') {
*(++p) = '.';
*(++p) = '\0';
len++;
}
if (!chdir(pathname)) {
if (len > 2 && *(pathname+1) == ':') /* device changed */
setdisk(*pathname - 'a' );
} else {
fprintf(stderr, "cannot chdir to %s\n", pathname);
return(1);
}
return(0);
} else return(-1);
}
int func_echo(int argc, char *argv[], int mode)
{
if (argc > 1)
fprintf(stdout, "%s\n", argv[1]);
return(0);
}
int func_exec(int argc, char *argv[], int mode)
{
if (argc > 1) {
char *buf = xmalloc(512);
char *buff = xmalloc(512);
char *p = buff;
int k = 0;
char **nargv;
while (++k < argc) {
strcpy(p, argv[k]);
p += strlen(argv[k]);
*p++ = 32;
*p = '\0';
}
nargv=build_argv(buf, 512, buff);
xfree(buff);
if (nargv != NULL) {
if (!mode)
spawnvp(P_WAIT, buf, nargv);
else
execvp(buf, nargv);
}
xfree(buf);
}
return(0);
}

View File

@ -21,7 +21,7 @@ RM = del
ASMODS= kern$(O)
CCMODS= tools$(O) netcall$(O) ncpcall$(O) \
login$(O) map$(O) slist$(O) nwcrypt$(O) \
nwdebug$(O) nwtests$(O)
nwdebug$(O) nwtests$(O) capture$(O)
all: net$(E)

155
map.c
View File

@ -24,6 +24,7 @@ static void show_map(uint8 *drvstr)
if ((!get_drive_info(j, &connid, &dhandle, &flags)) && flags){
char servern[52];
char path[256];
servern[0]='\0';
if (flags & 0x80) { /* lokal DRIVE */
path[0]= '\\';
if (j < 2){
@ -35,11 +36,11 @@ static void show_map(uint8 *drvstr)
if (get_dir_path(dhandle, path)) {
strcpy(path, "DHANDLE !OK");
}
if (connid) {
get_fs_name(connid, servern);
strcat(servern, "\\");
} else servern[0]='\0';
}
if (connid) {
get_fs_name(connid, servern);
strcat(servern, "\\");
} else servern[0]='\0';
printf("MAP %c: = %s%s\n", (char)j+'A', servern, path);
}
}
@ -76,22 +77,27 @@ static void do_map(int drive, NWPATH *nwp)
}
#endif
static int do_map(int drive, NWPATH *nwp)
static int do_map(int drive, NWPATH *nwp, int delete)
{
int result = -1;
if (drive > -1 && drive < 32) {
uint8 nmdrive[3];
nmdrive[0] = drive+'A';
nmdrive[1] = ':';
nmdrive[2] = '\0';
result = redir_device_drive(0x4, nmdrive, nwp->path);
uint8 connid;
uint8 dhandle;
uint8 flags;
if (!delete ||
(!get_drive_info(drive, &connid, &dhandle, &flags) && flags && connid)){
uint8 nmdrive[3];
nmdrive[0] = drive+'A';
nmdrive[1] = ':';
nmdrive[2] = '\0';
result = redir_device_drive(delete ? -1 : 0x4, nmdrive, nwp->path);
}
}
return(result);
}
static int parse_argv(uint8 *drvstr, NWPATH *nwpath,
int argc, char *argv[], int smode)
int argc, char *argv[], int smode, int argvmode)
{
int k = 0;
int mode = 0;
@ -149,7 +155,8 @@ static int parse_argv(uint8 *drvstr, NWPATH *nwpath,
} /* while *p */
} /* while k */
if (mode == 30) {
getcwd((char *)nwpath->buff, sizeof(nwpath->buff));
if (argvmode != 1)
getcwd((char *)nwpath->buff, sizeof(nwpath->buff));
mode = 40;
}
if (mode && mode != 20 && mode != 40) {
@ -159,21 +166,24 @@ static int parse_argv(uint8 *drvstr, NWPATH *nwpath,
return(0);
}
int func_map(int argc, char *argv[])
int func_map(int argc, char *argv[], int mode)
{
uint8 drvstr[22];
NWPATH nwpath;
if (!ipx_init()) argc = 1;
if (!parse_argv(drvstr, &nwpath, argc, argv, 0)) {
if (*(nwpath.path)) {
if (do_map(*drvstr - 'A', &nwpath)< 0)
if (!parse_argv(drvstr, &nwpath, argc, argv, 0, mode)) {
if (*(nwpath.path) || mode==1) {
if (do_map(*drvstr - 'A', &nwpath, mode)< 0)
fprintf(stderr, "MAP Error\n");
}
show_map(drvstr);
if (mode != 1)
show_map(drvstr);
return(0);
}
return(1);
}
/* ------------------------------------------------- */
static int show_search(uint8 *drvstr)
{
@ -183,38 +193,42 @@ static int show_search(uint8 *drvstr)
get_search_drive_vektor(drives);
while (p->drivenummer != 0xff && j++ < 16) {
char path[256];
char nwname[256];
char nwname_path[300];
if ( !*drvstr || j == *(drvstr+1)) {
if (p->flags && !(p->flags & 0x80)){
get_fs_name(p->u.fs.connid, nwname);
if (get_dir_path(p->u.fs.dhandle, path)) {
strcpy(path, "ERROR NW");
}
(void)xadd_char(nwname, '\\', 20);
if (p->drivenummer == 0xfe){
strcpy(path, p->dospath);
} else {
nwname[0] = '\0';
/*
nwname[0] = '<';
strcpy(nwname+1, "LOCAL");
*/
if (p->drivenummer == 0xfe){
strcpy(path, p->u.d.dospath);
} else if (getcurdir((int)(p->drivenummer)+1, path)) {
strcpy(path, "ERROR DOS");
}
/*
(void)xadd_char(nwname, '>', 20);
*/
*path = p->drivenummer+'A';
*(path+1) = ':';
strcpy(path+2, p->dospath);
}
strcat(nwname, path);
printf("SEARCH%2d = %c: %s\n", j, (char)(p->drivenummer)+'A', nwname);
if (p->flags && !(p->flags & 0x80)){
char *pp=nwname_path;
*pp++ = '[';
get_fs_name(p->connid, pp);
pp +=strlen(pp);
*pp++='\\';
if (get_dir_path(p->dhandle, pp)) {
strcpy(pp, "ERROR NW");
}
pp += strlen(pp);
*pp ++= ']';
*pp = '\0';
} else {
*nwname_path = '\0';
}
printf("SEARCH%2d = %s %s\n", j, path, nwname_path);
}
p++;
}
return(0);
}
static int set_search(uint8 *drvstr, NWPATH *nwp)
static int set_search(uint8 *drvstr, NWPATH *nwp, int pathmode)
{
int result=-1;
SEARCH_VECTOR drives;
@ -222,31 +236,78 @@ static int set_search(uint8 *drvstr, NWPATH *nwp)
int j=0;
int entry = (*drvstr=='s') ? *(drvstr+1) : 0;
get_search_drive_vektor(drives);
while (p->drivenummer != 0xff && j++ < 16) {
if (!entry && (p->drivenummer + 'A' == *drvstr)) entry=j;
if (p->drivenummer + 'A' == nwp->path[0] && nwp->path[1] == ':'
&& !strcmp(nwp->path+2, p->dospath)) {
p->drivenummer=0xfe;
*(p->dospath) = '\0';
}
p++;
}
if (entry > 0) {
if (entry > 16) entry = 16;
if (--entry < j) p = drives+entry;
if (pathmode == 2 && entry <= j && entry < 16) { /* insert modus */
int k=j+1-entry;
if (j < 16) {
p++;
k++;
j++;
}
while (k--) {
memcpy(p, p-1, sizeof(SEARCH_VECTOR_ENTRY));
--p;
}
}
if (--entry < j)
p = drives+entry;
else (p+1)->drivenummer = 0xff;
p->flags = 0;
p->drivenummer = 0xfe;
strcpy(p->u.d.dospath, nwp->path);
if (pathmode==1)
*(p->dospath) = '\0';
else
strcpy(p->dospath, nwp->path);
result = set_search_drive_vektor(drives);
}
return(result);
}
int func_path(int argc, char *argv[])
int func_path(int argc, char *argv[], int mode)
{
uint8 drvstr[22];
NWPATH nwpath;
if (!parse_argv(drvstr, &nwpath, argc, argv, 1)) {
if (!parse_argv(drvstr, &nwpath, argc, argv, 1, mode)) {
int result=0;
if (*(nwpath.path)) result=set_search(drvstr, &nwpath);
show_search(drvstr);
if (*(nwpath.path) || mode==1)
result=set_search(drvstr, &nwpath, mode);
if (mode != 1)
show_search(drvstr);
return(result);
}
return(1);
}
void remove_nwpathes(void)
{
SEARCH_VECTOR drives;
SEARCH_VECTOR_ENTRY *p=drives;
int j=0;
get_search_drive_vektor(drives);
while (p->drivenummer != 0xff && j++ < 16) {
if (p->flags && !(p->flags & 0x80)){
p->flags=0;
p->drivenummer=0xfe;
*(p->dospath) ='\0';
}
++p;
}
set_search_drive_vektor(drives);
}

16
mars_dosutils.lsm Normal file
View File

@ -0,0 +1,16 @@
Begin3
Title: mars_dosutils
Version: 0.10
Entered-date: 21-May-96
Description: Simple DOS client program specially
for mars_nwe.
Supports login, map, capture, passwd
Binary + sourcen
Keywords: novell, netware, client, ipx, ncp, mars_nwe
Author: mstover@freeway.de (Martin Stover)
Maintained-by: mstover@freeway.de (Martin Stover)
Primary-site: ftp.gwdg.de:/pub/linux/misc/ncpfs
60kB mars_dosutils-0.10.tgz
Platforms: DOS, DOSEMU
End

4
mk.bat
View File

@ -1,4 +0,0 @@
maker %1 %2 %3 %4 > err
type err
copy net.exe c:\
del net.exe

197
net.c
View File

@ -1,74 +1,123 @@
/* net.c 14-Mar-96 */
/* simple client programm to act with mars_nwe */
/****************************************************************
* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany *
****************************************************************/
#include "net.h"
char *funcname=NULL;
typedef int (*NET_FUNC)(int argc, char *argv[]);
static struct s_net_functions {
char *name;
char *description;
NET_FUNC func;
} net_functions[] = {
{"LOGIN", "login to Server as User" , func_login },
{"MAP", "list maps and map drives" , func_map },
{"PATH", "list and set search path" , func_path },
{"LOGOUT", "logout from Server", func_logout },
#if 0
{"SLIST", "list Servers", func_slist },
#endif
{"PASSWD", "change password", func_passwd },
#if 1
{"TESTS", "only testroutines!", func_tests },
#endif
{"DEBUG", "set debug level, for mars_nwe only !", func_debug }
};
#define MAX_FUNCS (sizeof(net_functions) / sizeof(struct s_net_functions))
int main(int argc, char *argv[])
{
NET_FUNC func = NULL;
int result = -1;
if (argc > 1) {
char funcn[200];
int k= MAX_FUNCS;
strmaxcpy(funcn, argv[1], sizeof(funcn)-1);
upstr(funcn);
while (k--) {
if (!strcmp(funcn, net_functions[k].name)) {
func=net_functions[k].func;
funcname=net_functions[k].name;
break;
}
}
}
if (func != NULL) {
if (ipx_init() || func == func_map) {
result = (*func) (argc-1, &(argv[1]));
}
} else {
int k= MAX_FUNCS;
char progname[256];
strmaxcpy(progname, argv[0], sizeof(progname)-1);
upstr(progname);
fprintf(stderr, "\n"
"****************************************************************\n"
"* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany *\n"
"****************************************************************\n\n" );
fprintf(stderr, "Usage:\t%s func ... \nfuncs:", progname);
while (k--) {
if (net_functions[k].func) {
fprintf(stderr, "\t%s\t: %s\n",
net_functions[k].name, net_functions[k].description);
}
}
}
return(result);
}
/* net.c */
#define VERS_DATE "21-May-96"
/* simple client program to act with mars_nwe */
/****************************************************************
* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany *
****************************************************************/
#include "net.h"
char *funcname=NULL;
char prgpath[65];
typedef int (*NET_FUNC)(int argc, char *argv[], int mode);
static struct s_net_functions {
char *name;
char *description;
NET_FUNC func;
int mode;
} net_functions[] = {
{"SPAWN", "spawn program(command file)" , func_exec , 0},
{"EXEC", "execute program(command file)", func_exec , 1},
{"ECHO", "echoes string (command file)" , func_echo , 0},
{"CD", "change directory (command file)" , func_cwd , 0},
{"LOGIN", "login to server as user" , func_login , 0},
{"PROFILE","read command file" , func_profile, 0},
{"CAPTURE","list and redirect printers" , func_capture, 0},
{"ENDCAP", "cancel redirect printers" , func_capture, 1},
{"MAP", "list maps and map drives" , func_map , 0},
{"MAPDEL", "removes maps" , func_map , 1},
{"PATH", "list and set search path" , func_path , 0},
{"PATHDEL","removes search path" , func_path , 1},
{"PATHINS","insert search path" , func_path , 2},
{"LOGOUT", "logout from server", func_logout , 0},
#if 0
{"SLIST", "list servers", func_slist , 0},
#endif
{"PASSWD", "change password", func_passwd , 0},
#if 1
{"TESTS", "only testroutines!", func_tests , 0},
#endif
{"DEBUG", "set debug level, for mars_nwe only !", func_debug , 0}
};
#define MAX_FUNCS (sizeof(net_functions) / sizeof(struct s_net_functions))
static int get_entry_nr(char *fstr)
{
int entry = MAX_FUNCS;
char buff[200];
char funcn[100];
char *pp;
strmaxcpy(buff, fstr, sizeof(buff)-1);
korrpath(buff);
get_path_fn(buff, NULL, funcn);
pp=strrchr(funcn, '.');
if (NULL != pp) *pp = '\0';
upstr(funcn);
while (entry--) {
if (!strcmp(funcn, net_functions[entry].name)) return(entry);
}
return(-1);
}
int call_func_entry(int argc, char *argv[])
{
int funcmode;
int result = -1;
NET_FUNC func = NULL;
int entry = get_entry_nr(argv[0]);
if (entry > -1) {
func = net_functions[entry].func;
funcmode = net_functions[entry].mode;
funcname = net_functions[entry].name;
}
if (NULL != func) {
if (ipx_init() || func == func_map) {
result = (*func)(argc, argv, funcmode);
} else {
fprintf(stderr, "Cannot init IPX\n");
}
} else result = -0xff;
return(result);
}
static void get_path(char *path)
{
char buf[100];
strmaxcpy(buf, path, sizeof(buf)-1);
korrpath(buf);
get_path_fn(buf, prgpath, NULL);
}
int main(int argc, char *argv[])
{
int result = -0xff;
get_path(argv[0]);
result = call_func_entry(argc, argv);
if (result == -0xff)
result = call_func_entry(argc-1, argv+1);
if (result == -0xff) {
int k= MAX_FUNCS;
char progname[256];
strmaxcpy(progname, argv[0], sizeof(progname)-1);
upstr(progname);
fprintf(stderr, "\n"
"* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany *\n"
" Version: %s\n\n", VERS_DATE);
fprintf(stderr, "Usage:\t%s func ... \nfuncs:", progname);
while (k--) {
if (net_functions[k].func) {
fprintf(stderr, "\t%s\t: %s\n",
net_functions[k].name, net_functions[k].description);
}
}
}
return(result);
}

BIN
net.exe

Binary file not shown.

62
net.h
View File

@ -1,4 +1,4 @@
/* net.h: 01-Feb-96 */
/* net.h: 20-May-96 */
/****************************************************************
* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany *
@ -17,6 +17,7 @@
#include <stdarg.h>
typedef unsigned int UI;
typedef unsigned int uint;
typedef unsigned char UC;
typedef unsigned char uint8;
typedef unsigned short int uint16;
@ -103,15 +104,31 @@ typedef struct {
#define NWBIND 5
/* net.c */
extern char *funcname;
extern char *funcname;
extern char prgpath[];
extern int call_func_entry(int argc, char *argv[]);
/* tools.c */
extern void clear_kb(void);
extern int key_pressed(void);
extern int ask_user(char *p, ...);
#define xfree(p) x_x_xfree((char **)&(p))
extern void x_x_xfree(char **p);
extern char *xmalloc(uint size);
extern char *xcmalloc(uint size);
extern int strmaxcpy(char *dest, char *source, int len);
extern char *xadd_char(char *s, int c, int maxlen);
extern uint8 *upstr(uint8 *s);
extern void korrpath(char *s);
extern void get_path_fn(char *s, char *p, char *fn);
#define reb(s) deb((s)),leb((s))
extern void deb(uint8 *s);
extern void leb(uint8 *s);
#define add_char(s, c) xadd_char((s), (c), -1)
@ -124,17 +141,11 @@ extern int putglobenv(char *option);
#define DRIVE_DELETE 3
typedef struct {
uint8 drivenummer; /* 0xff, 0xfe f<>r DOSPATH mit Pfad */
uint8 flags;
union {
struct {
char dospath[65];
} d;
struct fs {
uint8 connid;
uint8 dhandle;
} fs;
} u;
uint8 drivenummer; /* 0xff=last of list, 0xfe only DOSPATH */
uint8 flags; /* 0x80 = local drive */
char dospath[65];
uint8 connid;
uint8 dhandle;
} SEARCH_VECTOR_ENTRY;
typedef SEARCH_VECTOR_ENTRY SEARCH_VECTOR[17];
@ -180,23 +191,30 @@ extern int ncp_17_4b(uint8 *cryptkey, uint8 *objname, uint16 objtyp,
int passwx, uint8 *newpassword);
/* map.c */
extern int func_map(int argc, char *argv[]);
extern int func_path(int argc, char *argv[]);
extern int func_map (int argc, char *argv[], int mode);
extern int func_path (int argc, char *argv[], int mode);
/* login.c */
extern int func_login(int argc, char *argv[]);
extern int func_logout(int argc, char *argv[]);
extern int func_passwd(int argc, char *argv[]);
extern int func_login (int argc, char *argv[], int mode);
extern int func_logout (int argc, char *argv[], int mode);
extern int func_passwd (int argc, char *argv[], int mode);
extern int func_profile(int argc, char *argv[], int mode);
extern int func_cwd (int argc, char *argv[], int mode);
extern int func_echo (int argc, char *argv[], int mode);
extern int func_exec (int argc, char *argv[], int mode);
extern int read_command_file(char *fstr);
/* slist.c */
extern int func_slist(int argc, char *argv[]);
extern int func_slist (int argc, char *argv[], int mode);
/* nwdebug.c */
extern int func_debug(int argc, char *argv[]);
extern int func_debug (int argc, char *argv[], int mode);
/* nwtests.c */
extern int func_tests(int argc, char *argv[]);
extern int func_tests (int argc, char *argv[], int mode);
/* capture.c */
extern int func_capture(int argc, char *argv[], int mode);

View File

@ -49,6 +49,8 @@ int logout(void)
int redir_device_drive(int devicetyp, uint8 *devname, uint8 *remotename)
/* if devicetyp == -1, the redir is canceled */
/* devicetyp 3 = printer */
/* devicetyp 4 = disk drive */
{
REGS regs;
SREGS sregs;
@ -157,16 +159,15 @@ int get_search_drive_vektor(SEARCH_VECTOR_ENTRY *vec)
char *p1 = path;
int len = 0;
while (*path && *path++ !=';') len++;
if (*(p1+1) == ':'
&& *p1 >= 'A' && *p1 <= 'Z' &&
(len==2 || (len == 3 && *(p1+2) == '.'))) {
if (*(p1+1) == ':' && *p1 >= 'A' && *p1 <= 'Z') {
v->drivenummer = *p1 - 'A';
get_drive_info(v->drivenummer, &(v->u.fs.connid),
&(v->u.fs.dhandle), &(v->flags));
get_drive_info(v->drivenummer, &(v->connid),
&(v->dhandle), &(v->flags));
strmaxcpy(v->dospath, p1+2, min(len-2, sizeof(v->dospath)-1));
} else {
v->flags = 0;
v->drivenummer = 0xfe; /* ergibt ? */
strmaxcpy(v->u.d.dospath, p1, len);
strmaxcpy(v->dospath, p1, min(len, sizeof(v->dospath)-1));
}
(++v)->drivenummer = 0xff;
if (*path == ';') path++;
@ -181,20 +182,29 @@ int set_search_drive_vektor(SEARCH_VECTOR_ENTRY *vec)
char *p=path;
SEARCH_VECTOR_ENTRY *v;
int plen=strlen(path_env_name);
int maxcount=16;
strcpy(path, path_env_name);
path[plen] = '=';
path[++plen] = '\0';
while ((NULL != (v = vec++)) && v->drivenummer != 0xff){
if (p > path) *p++=';';
else p+=plen;
if (v->drivenummer < 26) {
*p++ = (char) v->drivenummer + 'A';
*p++ = ':';
*p++ = '.';
*p = '\0';
} else {
strcpy(p, v->u.d.dospath);
p+= strlen(v->u.d.dospath);
while (maxcount-- && (NULL != (v = vec++)) && v->drivenummer != 0xff){
if (v->drivenummer < 26 || *(v->dospath)) {
if (p > path) *p++=';';
else p+=plen;
if (v->drivenummer < 26) {
*p++ = (char) v->drivenummer + 'A';
*p++ = ':';
if (*v->dospath) {
strcpy(p, v->dospath);
p+= strlen(v->dospath);
} else {
*p++='.';
*p ='\0';
}
} else {
strcpy(p, v->dospath);
p+= strlen(v->dospath);
}
}
}
return(putglobenv(path));

View File

@ -1,4 +1,4 @@
/* nwdebug.c 04-Apr-96 */
/* nwdebug.c 21-May-96 */
/****************************************************************
* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany *
@ -13,7 +13,7 @@ static int usage(void)
return(-1);
}
int func_debug(int argc, char *argv[])
int func_debug(int argc, char *argv[], int mode)
{
uint8 s[200];
int module;
@ -29,8 +29,11 @@ int func_debug(int argc, char *argv[])
level = atoi(argv[2]);
if (level < 0 || level > 99) return(usage());
result = ncp_17_02(module, level);
if (result < 0) fprintf(stderr, "set debug failed\n");
else fprintf(stdout, "Debug level for %s changed from %d to %d\n",
if (result < 0) {
fprintf(stderr, "set debug failed\n");
fprintf(stderr, "perhaps you did not enable FUNC_17_02_IS_DEBUG\n");
fprintf(stderr, "in mars_nwe/config.h ?!");
} else fprintf(stdout, "Debug level for %s changed from %d to %d\n",
s, result, level);
return(result < 0 ? result : 0);
}

View File

@ -1,4 +1,4 @@
/* nwtests.c 14-Mar-96 */
/* nwtests.c 20-May-96 */
/****************************************************************
* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany *
@ -8,12 +8,10 @@
static int usage(void)
{
fprintf(stderr, "usage:\t%s NCPSERV|NWCONN level\n", funcname);
fprintf(stderr, "\tlevel=0 .. 99\n" );
return(-1);
}
int func_tests(int argc, char *argv[])
int func_tests(int argc, char *argv[], int mode)
{
int level = ncp_17_02(NWCONN, 6);
int dirhandle = alloc_temp_dir_handle(0, "SYS:", 'd', NULL);

View File

@ -6,7 +6,7 @@
#include "net.h"
int func_slist(int argc, char *argv[])
int func_slist(int argc, char *argv[], int mode)
{

95
tools.c
View File

@ -48,6 +48,31 @@ int ask_user(char *p, ...)
return(flag);
}
char *xmalloc(uint size)
{
char *p = (size) ? (char *)malloc(size) : (char*)NULL;
if (p == (char *)NULL && size){
fprintf(stderr, "not enough core, need %d Bytes\n", size);
exit(1);
}
return(p);
}
char *xcmalloc(uint size)
{
char *p = xmalloc(size);
if (size) memset(p, 0, size);
return(p);
}
void x_x_xfree(char **p)
{
if (*p != (char *)NULL){
free(*p);
*p = (char*)NULL;
}
}
int strmaxcpy(char *dest, char *source, int len)
/* copied max. len chars + '\0' Byte */
{
@ -69,6 +94,18 @@ char *xadd_char(char *s, int c, int maxlen)
return(s);
}
static uint8 down_char(uint8 ch)
{
if (ch > 64 && ch < 91) return(ch + 32);
switch(ch){
case 142: ch = 132; break;
case 153: ch = 148; break;
case 154: ch = 129; break;
default :break;
}
return(ch);
}
static uint8 up_char(uint8 ch)
{
if (ch > 96 && ch < 123) return(ch - 32);
@ -88,6 +125,64 @@ uint8 *upstr(uint8 *s)
return(s);
}
void deb(uint8 *s)
{
if (!s || !*s) return;
else {
uint8 *p = s + strlen(s);
while (p > s && (*--p==32 || *p==9));;
if (*p==32 || *p==9) *p='\0';
else *(p+1) = '\0';
}
}
void leb(uint8 *s)
{
if (!s || !*s || (*s != 32 && *s != 9)) return;
else {
uint8 *p = s;
for (;*p && *p!=32 && *p!=9;p++);;
strcpy(s, p);
}
}
void korrpath(char *s)
{
if (!s) return;
for (;*s;s++) {
if (*s=='\\') *s='/';
else *s=down_char(*s);
}
}
void get_path_fn(char *s, char *p, char *fn)
{
int j= strlen(s);
if (p != (char *)NULL) p[0] = 0;
if (fn != (char*) NULL) fn[0] = 0;
if (!j) return;
if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0) ) ) {
if (p != (char *)NULL) {
strcpy(p, s);
strcat(p, "/");
}
if (fn != (char *)NULL) fn[0] = 0;
return;
}
while (j--){
if ((s[j] == '/') || (s[j] == ':') ) {
if (fn != (char *)NULL) strcpy(fn, s+j+1);
if (p != (char *)NULL) {
strncpy(p, s, j+1);
p[j+1] = 0;
}
return;
}
}
if (fn != (char *)NULL) strcpy(fn, s); /* no path */
}
typedef struct {
uint16 adr1;
uint16 adr2;