%1~ SMILEY.BCKYҰ SMILEY.BCK%BACK SM:[*]*.* PUB:[PC]SMILEY.BCK/SAV BROWN_N |@V5.4 _DECUSF::  _$1$DIA1: V5.4 ~  *[000000]CLIB.DIR;1+,8./|@ 4-\40123 KPWO56 z7@"89G|@HJI  CALLENV.C8  CALLENV.H8FARSTR.C8FARSTR.H8 MOVEDATA.C8 MOVEDATA.H8*[CLIB]CALLENV.C;1+,8 . /|@ 4K f-80123KPWO 56 'I7 D89G|@HJ/* * CALLENV.C1 * Changes variables in the caller's environment. */#include #include "farstr.h"#include "movedata.h"#include "callenv.h"/*H * First few bytes of a PSP. Our env is at 2CH, caller's PSP is at 16H.D * Note that in some cases, this may also be the current program, so, * beware if you use try to follow a chain. */typedef struct { char stuff [22]; unsigned short prev_psp; char morestuff [20]; unsigned short local_env;} PSP;/*? * Put variable VAR in the caller's environment with value STR.) * VAR should have NO terminating = here.F * Returns CE_NOSPACE if insufficient space (currently NOT checked !). */int"put_callenv (char *var, char *str){ PSP far *mypsp; PSP far *call_psp; char far *env; short far *envparas; char vareq [80]; _AH = 0x62; geninterrupt(0x21); mypsp = MK_FP(_BX, 0);/*7 * Undocumented nasty hack: caller's PSP is in our PSP. */' call_psp = MK_FP(mypsp->prev_psp, 0);/*5 * Legitimate: get caller's environment from its PSP. */& env = MK_FP(call_psp->local_env, 0);/* * Really horrible hack:< * Environment size is 13 bytes before start of environment. *// envparas = MK_FP(call_psp->local_env - 1, 3);/*! * Add terminating = to variable. */ strcpy(vareq, var); strcat(vareq, "=");1 return put_any_env(env, *envparas, vareq, str);}/*; * Put variable VAR with value STR into environment at ENV.) * Total size of ENV is PARAS * 16 bytes. */>put_any_env (char far *env, short paras, char *var, char *str){ char far *ep; short bytes = paras * 16;. int lvs; /* Length of VAR plus = and STR. */ int newvar;" lvs = strlen(var) + strlen(str);/*/ * First find the existing value, if it exists. */ ep = env; newvar = 1; while (*ep) {+ if (!f2strncmp(var, ep, strlen(var))) {/*5 * Find the end of the environment (double NUL byte). */ int eplen = f1strlen(ep);$ char far *sp = ep + eplen + 1; char far *lp = sp; char far *tp; while (*lp) { lp += f1strlen(lp) + 1; }/*< * Check first that there will be room to add the new value. */C if (((FP_OFF(lp) - FP_OFF (env)) + (lvs - eplen)) >= bytes) { return CE_NOSPACE; }/*K * Move the rest of the environment to allow room for the new value of VAR.5 * If the new value is empty, overwrite VAR= as well. */ if (*str) {/ tp = sp + strlen(str) - (eplen - strlen(var)); } else { tp = ep; }) my_movedata(FP_SEG(sp), FP_OFF(sp), FP_SEG(tp), FP_OFF(tp),! (FP_OFF(lp) - FP_OFF(sp) + 1) ); /*- * Now move the new string value into place. */ if (*str) {; movedata(FP_SEG((char far *)str), FP_OFF((char far *)str),6 FP_SEG(ep + strlen(var)), FP_OFF(ep + strlen(var)), strlen(str) + 1 ); } newvar = 0; break; } else { ep += f1strlen(ep) + 1; } }/*F * If VAR did not exist, ep points to the end of the environment here.1 * Add the VAR/STR pair now, if STR is not empty. */ if ((newvar) && (*str)) {: if (((FP_OFF(ep) - FP_OFF(env)) + lvs + 1) >= bytes) { return CE_NOSPACE; } f1strcpy(ep, var); f1strcat(ep, str); ep[f1strlen(ep) + 1] = '\0'; } return CE_OK;}*[CLIB]CALLENV.H;1+,8./|@ 4C-80123KPWO56oe7E89G|@HJ/*& * CALLENV.H - includes for CALLENV.C. */#define CE_NOSPACE 1#define CE_OK 0'int put_callenv (char *var, char *str);Cint put_any_env (char far *env, short paras, char *var, char *str);*[CLIB]FARSTR.C;1+,8./|@ 436-80123KPWO56YJ7ࢂG89G|@HJ/* * FARSTR.C3 * String routines with one or more far parameters. */#include "farstr.h"/*0 * Version of STRNCMP with a far second pointer. */+f2strncmp (char *s1, char far *s2, int len){ while ((*s1) && (len)) { if (*s1 > *s2) { return 1; } else if (*s1 < *s2) { return -1; } else { ++s1; ++s2; --len; } } return 0;}/*. * Version of STRCPY with a far first pointer. */ char far *'f1strcpy (char far *s1, const char *s2){ char far *result = s1; do { *s1++ = *s2; } while (*s2++); return result;}/*. * Version of STRCAT with a far first pointer. */ char far *'f1strcat (char far *s1, const char *s2){ char far *result = s1; int len = f1strlen(s1); s1[len + strlen(s2)] = '\0'; while (*s2) { s1[len++] = *s2++; } return result;}/*( * Version of STRLEN with a far pointer. */f1strlen (char far *s){ int l = 0; while (*s++) { ++l; } return l;}*[CLIB]FARSTR.H;1+,8./|@ 42-80123KPWO56#include "movedata.h".my_movedata (unsigned srcseg, unsigned srcoff,' unsigned dstseg, unsigned dstoff, unsigned n){ char huge *hsrc; char huge *hdst;/*C * If the areas overlap, and dst > src, we must move bytes by hand. */ hsrc = MK_FP(srcseg, srcoff); hdst = MK_FP(dstseg, dstoff);- if ((hdst > hsrc) && ((hdst - hsrc) < n)) { while (n--) { hdst[n] = hsrc[n]; } } else {0 movedata(srcseg, srcoff, dstseg, dstoff, n); }}*[CLIB]MOVEDATA.H;1+,8./|@ 42-80123KPWO56@ h7JJ89G|@HJ/*( * MOVEDATA.H - includes for MOVEDATA.C. */2int my_movedata (unsigned srcseg, unsigned srcoff,+ unsigned dstseg, unsigned dstoff, unsigned n);*[000000]MOLE.DIR;1+,8./|@ 4-\40123 KPWO567#89G|@HJI MOLE.ASML8VMOLE.EXE/*[MOLE]MOLE.ASM;1+,L8V.B/|@ 4OBB-80123KPWOC56y!7<48g'p9G|@HJ,; MOLE.ASM - a resident DECnet-DOS listener.7; Copyright (C) Nick Brown, 1991. All rights reserved.;; Revision history:;; 21-OCT-1991 V0.43; Support DOS 5.2; Fix bug (label typo) in file handling for DOS 4.K; Zero out PSP environment pointer, so memory chain followers don't see it.;; 15-OCT-1991 V0.429; Close all standard file handles (0-4) before going TSR.;; 30-AUG-1991 V0.41N; Fixed bug whereby last few bytes of TSR data segment could be overwritten ifG; this was not moved to an allocated block (typically, if MOLE was runA; early in the boot process, before a hole was found in memory).;; 28-AUG-1991 V0.405; First public release. Version number is arbitrary.;J; This program is assembled and linked using some slightly unusual segment=; structures, in order to use an absolute minimum of memory.K; There are five conceptual (four real) segments, which are linked in order; as follows:; - TSR resident code (_TEXT)$; - TSR resident data (DATAX part 1)(; - TSR non-resident data (DATAX part 2)!; - TSR non-resident code (ZTEXT); - Stack (_STACK);N; The TSR resident data may be moved to another location. When the program isJ; run, it looks for a chunk of DOS memory large enough to accommodate theL; resident data (typically about 250 bytes) and before the current program;I; this is typically a hole in memory left by a previous TSR deallocatingL; its environment. If found, our resident data is moved there, and the TSR+; resident size is just the size of _TEXT.L; If we did not go through this procedure, it would be fine to have a single); code/data segment, arranged like this:; - TSR resident code; - TSR resident data; - TSR non-resident code; - TSR non-resident data;; Assembly options.; JUMPS LOCALS;I; TSR == 1 means the program will run as a TSR. This is normally what we; want, except for debugging.; TSR EQU 1 DEBUG EQU 1;O; Allow certain parts of the code to be omitted, for space and/or repliability.I; CLOSE == 0 omits the code which recognises the command 'Z'. If this isA; omitted, the TSR will listen for ever, and cannot be disabled.A; FILES == 0 omits the code which lists the open Files on the PC.;<CLOSE EQU 1 ;"Closedown" (stop listening) command recognised,FILES EQU 1 ;"Open files" request recognised;; DECnet-DOS definitions.;%NOLIST include dn.inc%LIST;; Debug macro definitions.;%NOLIST include gasp.inc%LIST;-; Size of variable part of a DECnet-DOS IOCB.;'S_PLIST EQU SIZE NIOCB_STRUC - io_plist;'; Macro to call DECnet network process.1; Currently just a subroutine call to save space.; DNPcall MACRO call dnp ENDM;D; Macro to output a string followed by carriage return and linefeed.;Say MACRO stringIF DEBUG AND (NOT TSR) Gasp &string&<,>13<,>10ENDIF ;IF DEBUG AND (NOT TSR); ENDM;D; Symbols for commands received from SMILEY (the MOLE's controller).J; To allow SMILEY to be replaced by a simpler procedure (eg in DCL), these'; are all upper-case ASCII characters.;"BREAK EQU 'B' ;Simulate ctrl/break COLDB EQU 'C' ;Perform cold boot1GETENV EQU 'E' ;Get whole of caller's environmentIF FILES"FILE1 EQU 'F' ;Get first open file'FILEn EQU 'G' ;Get subsequent open file ENDIF ;FILES!KEYHIT EQU 'K' ;Simulated key hit*NUMBER EQU 'N' ;Get program version number&CURSOR EQU 'P' ;Get cursor information1SETENV EQU 'S' ;Set whole of caller's environmentVIDEO EQU 'V' ;Get video buffer WARMB EQU 'W' ;Perform warm bootBYEBYE EQU 'X' ;See you laterIF CLOSE,GO_DEAF EQU 'Z' ;Tell MOLE to stop listeningENDIF ;IF CLOSE;; PSP structure.L; To be really mean with memory, we put our read and write buffers on top of%; the command-line parameters later.; PSP STRUC psp_stuff1 DB 22 DUP (?) psp_prevpsp DW ? psp_stuff2 DB 20 DUP (?) psp_envseg DW ? psp_stuff3 DB 82 DUP (?) psp_param_len DB ?) psp_params_1 DB 100 DUP (?) ;read buffer) psp_params_2 DB 26 DUP (?) ;write buffer psp_param_end DB ?PSP ENDSIF FILES;; DOS open file structure.; FILE STRUC num_handles DW ? open_mode DW ? fattr DB ? dev_info DW ? pointer DD ? start_cluster DW ? time DW ? date DW ? fsize DD ? offsett DD ? rel_cluster DW ? abs_cluster DW ? dir_sector DW ? dir_entry DB ? filename DB 11 DUP (?) share_prev_sft DD ? share_net_mach DW ? owner_psp DW ? FILE ENDS;; System file table structure.; SYSFTAB STRUC next DD ? nfiles DW ? first_file FILE ? SYSFTAB ENDSENDIF ;IF FILES;%; Proper code generation starts here.;CODEgrp GROUP _TEXT, ZTEXT .MODEL small!_STACK SEGMENT PARA STACK 'STACK' DB 256 DUP (?) _STACK ENDS;O; For some reason, if there is a data segment called _DATA, accesses to it failN; when the main code segment is given the 'DATA' attribute. So we use DATAX.N; This segment is paragraph aligned, so that when we move it to a memory block3; which we obtain from DOS, the offsets will work.; DATAX SEGMENT PARA PUBLIC 'DATA' dattop EQU $;3; DECnet-DOS I/O control blocks for each operation.H; The alternative to having one for each operation is to have two commonD; structures and alternate between them (when handling asynchronousD; completion of a DNP call, we must not jump on the original IOCB).;%ac_iocb NIOCB_STRUC . ORG $ - S_PLIST ;back up for attach structure: ATTACH_STRUC : ORG $ - SIZE ATTACH_STRUC ;back up for sockaddr structure SOCKADDR_STRUC ?;%sl_iocb NIOCB_STRUC . ORG $ - S_PLIST ;back up for select structure SELECT_STRUC ;#rd_iocb NIOCB_STRUC . ORG $ - S_PLIST ;back up for buffer structure BUFFER_STRUC ;#rx_iocb NIOCB_STRUC . ORG $ - S_PLIST ;back up for buffer structure BUFFER_STRUC ;#wr_iocb NIOCB_STRUC . ORG $ - S_PLIST ;back up for buffer structure BUFFER_STRUC ;)ds_iocb NIOCB_STRUC . ORG $ - S_PLIST ;back up (no other structure);%dt_iocb NIOCB_STRUC . ORG $ - S_PLIST ;back up (no other structure);%dl_iocb NIOCB_STRUC . ORG $ - S_PLIST ;back up (no other structure)IF CLOSE;; Closedown flags.;$closedn DB ? ;Closedown in progressIFE TSR!stopnow DB 0 ;Closedown finishedENDIF ;IFE TSRENDIF ;IF CLOSEIF FILES;#; Data for open file manipulations.;.fnok DB 0 ;FILEn operation allowed (1 == yes)&ofbsize DW ? ;Size of open file blocksfts DD ? ;Current SFT address,ofile DD ? ;Current open file block address'sftnf DW ? ;Count of files in this SFT5newsft DB ? ;Current SFT is just starting (1 == yes)LofL DD ? ;DOS List of ListsENDIF ;IF FILES;3; Segment address and size of caller's environment.; callenv DW ? cesize DW ?; ; This program's version number.;vernum DB '0.43'vernum_len EQU $ - vernum;C; This is the end of the data that will remain resident in the TSR.;datsize EQU $ - dattop;A; Data from this point on should not be referenced from TSR code.J; I would like to start another segment here, but it doesn't seem to work.;%at_iocb NIOCB_STRUC . ORG $ - S_PLIST ;back up for attach structure: ATTACH_STRUC <0, AF_DECnet, SOCK_SEQPACKET, AF_NSP, 0, 0>;; Our object number is 136...;OurObj EQU 136;#bn_iocb NIOCB_STRUC . ORG $ - S_PLIST ;back up for socket structure/ SOCKADDR_STRUC ;%ls_iocb NIOCB_STRUC 0 ORG $ - S_PLIST ;back up for listener structure LISTEN_STRUC <1>;(no_dnp DB 'DNP not running', 13, 10, '$';IF FILESAbad_dos DB 'Only DOS versions 3 through 5 supported', 13, 10, '$'ENDIF ;IF FILESIF TSR;0; Error message for deallocation of environment.;de_msg DB 'Error '5de_code DB '00 deallocating environment', 13, 10, '$' ENDIF ;IF TSRIFE TSR;B; DNP error message - codes filled in with hex numbers at runtime.;dn_msg DB 'DNP error 'dn_code DB '0000 in function 'dn_fun DB '00', 13, 10, '$'ENDIF ;IFE TSRIF DEBUG AND (NOT TSR)zmsg DB 'Our PSP address '#zpsp DB '0000, caller PSP address '$zcpsp DB '0000, caller env address '#zaddr DB '0000, caller env size 0x'zsize DB '0000', 13, 10, '$'ENDIF ;IF DEBUG AND (NOT TSR);J; Nxt variable tells us whether we should reset interrupt vectors on exit.;#vecset DB 0 ;Vectors remapped yet ? DATAX ENDS _TEXT SEGMENT WORD PUBLIC 'CODE' txttop EQU $ ASSUME CS:CODEgrp ASSUME DS:DATAX;; Saved interrupt vectors.;vec16 DD ?;.; Simulated key hit (character and scan code).; simkey DW 0;; Handler for interrupt 16H.;int16 PROC FAR push bx mov bx, ax; or ah, ah je @@fun_00_or_10 cmp ah, 01H je @@fun_01_or_11 cmp ah, 10H je @@fun_00_or_10 cmp ah, 11H je @@fun_01_or_11 jmp @@ignore;+; Return (and clear) any simulated key hit.;@@fun_00_or_10: mov ax, cs:[simkey]0 or ax, ax ;simkey is zero if no code available* je @@ignore ;maybe there's a real key hit, mov cs:[simkey], 0 ;clear simulated key hit pop bx; iret;"; Check for any simulated key hit.;@@fun_01_or_11: mov ax, cs:[simkey]0 or ax, ax ;simkey is zero if no code available* je @@ignore ;maybe there's a real key hit pop bx;" retf 2 ;return preserving Z flag;,; Come here if no simulated key hit waiting.; @@ignore: mov ax, bx pop bx;#; Jump to "real" interrupt handler.; int16_end: jmp cs:[vec16] int16 ENDP;B; Subroutine to call DNP (could be a macro, but this saves bytes).;dnp: push dx mov dx, bx0 mov ax, 0de01H ;IOCB request and DNP specifier int 6eH ;DECnet interrupt pop dxIFE TSR& cmp [bx.io_errno], -1 ;Get error code& je dnp_error ;Jump if error detected ENDIF ;IF TSR ret;+; Callback routine for asynchronous select.;call_sl PROC FARIF DEBUG Say 'Callback (select)'ENDIF ;IF DEBUGIFE TSR;); Check that a read socket was specified.K; If no timeout is specified, this should be the only way we can come here.;' cmp WORD PTR [bx.io_plist.sel_read], 0 jne @@Some_IOIF DEBUG Say 'Timeout'ENDIF ;IF DEBUG call do_sl retf @@Some_IO:ENDIF ;IFE TSR;; Accept connection.; mov bx, OFFSET ac_iocb;' mov ax, [dl_iocb.io_socket] ;Listener! mov [bx.io_plist.att_socket], ax;IF DEBUG Say 'Accept'ENDIF ;IF DEBUG DNPcall; retf call_sl ENDP;+; Callback routine for asynchronous accept.;call_ac PROC FARIF DEBUG Say 'Callback (accept)'ENDIF ;IF DEBUG;4; Put active socket number into IOCBs which need it.; mov ax, [bx.io_socket] mov [ds_iocb.io_socket], ax mov [wr_iocb.io_socket], ax mov [dt_iocb.io_socket], ax mov [rd_iocb.io_socket], ax mov [rx_iocb.io_socket], ax;; Schedule read.; call do_rd; retf call_ac ENDP;); Callback routine for asynchronous read.;call_rd PROC FARIF DEBUG Say 'Callback (read)'ENDIF ;IF DEBUG; push es;; Save count of bytes read.; mov ax, [bx.io_plist.io_buflen]$ mov di, ax ;DI is available for us;<; EOF or zero bytes read or 'X' means start listening again.; or ax, ax! je @@eof ;go if zero bytes read* les si, DWORD PTR [bx.io_plist.io_buffer]+ mov al, es:[si] ;get first byte of command cmp al, BYEBYE ;is it an 'X' ? je @@eof ;go if so;IF CLOSE;5; 'Z' means stop listening (TSR) or exit (otherwise).; cmp al, GO_DEAFENDIF ;IF CLOSE, jne @@no_close ;go if not closedown requestIF CLOSE mov ah, 1ENDIF ;IF CLOSE;H; Close down current remote connection; possibly stop listening as well.;@@eof:IF CLOSE. mov [closedn], ah ;1 == closedown altogetherENDIF ;IF CLOSE;'; Schedule disconnect of active socket.; mov bx, OFFSET ds_iocb;IF DEBUG Say 'Disconnect'ENDIF ;IF DEBUG jmp @@sched; @@no_close: cmp al, COLDB jne @@no_coldboot;; Perform cold boot.;' xor cx, cx ;Magic boot parameter = 0 jmp @@boot;; Not cold boot request.;@@no_coldboot: cmp al, WARMB jne @@no_warmboot;; Perform warm boot.;- mov cx, 1234H ;Magic boot parameter = 1234H;&; Cold and warm boot code merges here.;@@boot: xor ax, ax& mov ds, ax ;Magic boot parameter...& mov bx, 0472H ;... goes at 0000:0472 mov WORD PTR [bx], cx dec ax ;Push segment FFFF push ax inc ax ;Push offset 0 push ax retf ;Jump to FFFF:0000; ; Not cold or warm boot request.;@@no_warmboot: cmp al, SETENV jne @@no_setenv;-; Schedule bulk read to caller's environment.; mov bx, OFFSET rx_iocb1 mov ax, [callenv] ;Caller's environment address( mov WORD PTR [bx.io_plist.io_buffer], 0+ mov WORD PTR [bx.io_plist.io_buffer+2], ax- mov ax, [cesize] ;Caller's environment size) mov WORD PTR [bx.io_plist.io_buflen], ax;IF DEBUG Say 'Big read'ENDIF ;IF DEBUG jmp @@sched;!; Not request to set environment.; @@no_setenv: cmp al, BREAK jne @@no_break;#; Request for simulated ctrl/break.; int 1BH jmp @@sched;!; Not request for version number.; @@no_break:;<; From this point on, all received characters cause a reply.;; Functions not needing a reply should be coded above here.; cmp al, GETENV jne @@no_env;$; Send entire environment to caller.; xor si, si mov es, [callenv] mov ax, [cesize] jmp @@do_reply; @@no_env: cmp al, VIDEO jne @@no_screen;); Send entire character screen to caller.; xor si, si mov ax, 0B800H mov es, ax mov ax, 4000 jmp @@do_reply;; Not request for screen.; @@no_screen:IF FILES cmp al, FILE1 jne @@no_file1;; Request for first open file.;; Get List of Lists.; les bx, [LofL];; Get first SFT to ES:BX; les bx, DWORD PTR es:[bx+4]3 mov WORD PTR [sfts], bx ;Save offset of first SFT.6 mov WORD PTR [sfts+2], es ;Save segment of first SFT.# mov [fnok], 1 ;FILEn allowed now.7 mov [newsft], 1 ;This SFT has not been looked at yet. jmp @@anyfile;; Not request for first file.; @@no_file1: cmp al, FILEn jne @@no_filen;; Request for next open file.; cmp [fnok], 0( je @@filen_nogo ;Not currently allowed;; Get current SFT to ES:BX; les bx, [sfts];:; Come here with SFT set up in ES:BX, ready for next file.; @@anyfile:. cmp [newsft], 1 ;First time round this SFT ? jne @@not_new_sft ;Jump if not1 dec [newsft] ;Now not first time round this SFTIF DEBUG Say 'New SFT'ENDIF ;IF DEBUG3 mov ax, es:[bx.nfiles] ;count of files in this SFT* or ax, ax ;are there any files at all ?$ je @@end_sft ;if not, get next SFT+ mov [sftnf], ax ;save count for file loop) add bx, first_file ;point to first file jmp @@file_ready ;process file;C; If this is not a new SFT, load the previously saved file pointer.;@@not_new_sft:( les bx, [ofile] ;saved last time round;9; Here, ES:BX points to the next unseen file in this SFT.; @@file_ready:? mov cx, es:[bx.num_handles] ;get handle count - check it lateri* mov si, bx ;save current file offset...! mov ax, es ;... and segment...1 mov di, ax ;... for later; ); Skip to next file or start of next SFT.O;., dec [sftnf] ;any more files in this SFT ?, je @@end_sft ;if not, go and start new SFT2 add bx, [ofbsize] ;skip to next file in this SFT. mov WORD PTR [ofile], bx ;save file offset...: mov WORD PTR [ofile+2], es ;... and segment for next timeIF DEBUG Say 'New file nex"t time' ENDIF ;IF DEBUGa9 jmp @@poss_reply ;see if previous file needs to be sentp;e; Get next SFT...a;o @@end_sft:* mov bx, WORD PTR [sfts] ;get previous SFT( les bx, es:[bx.next] ;chain to next SFT mov ax, ess- or ax, ax ;zero segment means no more SFTsg je @@filen_nogo- cmp bx, -1 ;FFFF offset means no more SFTsm je @@filen_nogoIF DEBUG Say 'New SFT next time'ENDIF ;IF DEBUGc, mov WORD PTR [sfts], bx ;save offset of SFT/ mov WORD PTR [sfts+2], es ;save segment of SFTT) mov [newsft], 1 ;start of SFT next timeX @@poss_reply:S' or cx, cx ;was previous file valid ?_ je @@anyfile ;jump if nott;t<; Come here if file is open: DI:SI (sic) is open file block.; * mov ax, di ;retrieve segment from DI... mov es, ax ;... to ES8 add si, filename ;point to filename in open file block jmp @@file_reply ;send reply;lI; Come here is FILEn is not currently valid (last file already requested,tK; or no previous FILE1 seen). Return a filename whose first byte is zero,i2; and make sure FNOK is zero for next time round."; Then fall through to send reply.;h @@filen_nogo: 5 mov si, OFFSET fnok ;Point to FNOK which we know...e0 mov BYTE PTR [si], 0 ;(as we are setting it)... mov ax, ds ;... is a zero.t mov es, ax ;e@; Come here (by jump or falling through) with ES:SI == filename.;m @@file_reply:T mov ax, 11n jmp @@do_reply;w; Not request for next file.;S @@no_filen:U ENDIF ;FILES cmp al, NUMBERt jne @@no_number;m; Request %for version number.i;y- mov si, OFFSET vernum ;version number strings mov ax, ds'! mov es, ax ;data segment to ESS) mov ax, vernum_len ;string length to AXl jmp @@do_reply0;i!; Not request for version number.l;o @@no_number: cmp al, CURSORs jne @@no_cursor;g; Request for cursor position.;" mov ah, 0fH ;get video state int 10H;S mov di, dx2 mov ah, 03H ;get cursor position and attributes int 10H;i> mov si, OFFSET psp_params_2 ;ES already points to PSP segment/ mov WORD PTR es:[si], dx ;save cursor positionL3 mov WORD PTR es:[si+2], cx ;save cursor attributeso;l mov dx, dio;p mov ax, 4 jmp @@do_replys;o"; Not request for cursor position.; @@no_cursor: cmp al, KEYHIT jne @@no_keyhit; E; Simulated key hit. Next two data bytes are key code and scan code.E; See if a key hit is already waiting to be picked up by a BIOS call.N;T xor ax, axD cmp cs:[simkey], ax jne @@already; %; No key hit pending - save this one. ;a mov bx, WORD PTR es:[si+1]  mov cs:[simkey], bx inc ax,;e?; Merge here to send reply (says whether key hit was accepted).S;l @@already:> mov si, OFFSET psp_params_2 ;ES already points to PSP segment3 mov BYTE PTR es:[si], al ;save reply code (0 or 1)G mov ax, 1 jmp @@do_reply ; ; Not simulated key hit.;N @@no_keyhit:;HB; Unrecognised command, so just echo received character plus star.;b mov ax, diU' inc ax ;Write count = read count + 1', add di, si ;Point past last received byte() mov BYTE PTR es:[di], '*' ;Insert a starP;o; Merge here to write reply.; At this point:); ES:SI == address of bytes to be writtenp$; AX == count of bytes to be written; @@do_reply: . mov bx, OFFSET wr_iocb ;Ready to set up reply) mov WORD PTR [bx.io_plist.io_buffer], sil+ mov WORD PTR [bx.io_plist.io_buffer+2], ess mov [bx.io_plist.io_buflen], axIF DEBUG Say 'Write'ENDIF ;IF DEBUGv;W@; Come here with desired IOCB in BX, to schedule next operation.;B@@sched: DNPcall;ePh'7~ SMILEY.BCKL8V8[MOLE]MOLE.ASM;1OB) pop esp;m retf2 call_rd ENDP;fL; Callback routine for asynchronous read of large buffer directly to target.;call_rx PROC FARIF DEBUG Say 'Callback (rx)'ENDIF ;IF DEBUGd;f; Reschedule read.; call do_rdr;  retfm call_rx ENDP;*; Callback routine for asynchronous write.; call_wr PROC FARIF DEBUG Say 'Callback (write)' ENDIF ;IF DEBUG1; ; Reschedule read.;D call do_rdt;c retf call_wr ENDP;E/; Callback routine for asynchronous disconnect.;Fcall_ds PROC FARIF DEBUG Say 'Callback (disconnect)'ENDIF ;IF DEBUGN mov bx, OFFSET dt_iocbpIF DEBUG Say 'Detach active socket'EENDIF ;IF DEBUGZ DNPcall;m retf call_ds ENDP;T<; Callback routine for asynchronous detach of active socket.;acall_dt PROC FARIF DEBUG Say 'Callback (detach active)'iENDIF ;IF DEBUGa;d*; If closedown requested, detach listener.:; Otherwise re-issue select to listen for new connections.;eIF CLOSE cmp [clos+edn], 1 je do_closeENDIF ;IF CLOSEeIF DEBUG Say 'Select (again)'MENDIF ;IF DEBUGD call do_slU retf;E do_close:O mov bx, OFFSET dl_iocbo;aIF DEBUG Say 'Detach listener socket' ENDIF ;IF DEBUG  DNPcall;m retfs call_dt ENDP;t>; Callback routine for asynchronous detach of listener socket.O; This indicates that the program should exit (or stop listening, for the TSR).C;,call_dl PROC FARIF DEBUG! Say 'Callback (detach listener)'SENDIF ;IF DEBUGC;cG; If TSR, zap interrupt routines with NOPs vectors here (if debugging),?G; so that they will not run when other versions of the TSR are loaded.aD; Note that we cannot really just put back the old interrupt vector,I; since (1) we can't call DOS (OK, I know DOS just jumps on the vector),?G; and more seriously (2) another TSR, loaded after us, might have alsot; remapped this vector.3; If not TSR, set flag so user wait loop will exit.?;IF TSRIF DEBUG push es;_ mov ax, cs mov es, ax  mov al, 90H ;NOP instruction cld ;we are incrementingf;s mov di, OFFSET int16  mov cx, int16_end - int16+ cli ;prevent interrupts while we do thisY rep stosb sti;\ pop es,ENDIF ;IF DEBUGCELSEIF CLOSE( mov [stopnow], 1 ;will exit after thisENDIF ;IF CLOSE?ENDIF ;IF TSR ELSE;U retfS call_dl ENDP;I'; Subroutine to select listener socket.?<; Preserves DX, as it may be called from a callback routine.;o do_sl PROC mov bx, OFFSET sl_iocb IFE TS.Ri; D; If not TSR, specify a timeout, just so we see something happening.;L+ mov WORD PTR [bx.io_plist.sel_seconds], 10SENDIF ;IFE TSR;t; Set up socket masks.; read: just listener.,; write and exception: none (already setup)."; max socket number: listener + 1.;' mov cx, [dl_iocb.io_socket] ;Listenert mov ax, 1 shl ax, clT( mov WORD PTR [bx.io_plist.sel_read], ax inc cxO mov [bx.io_plist.sel_nfds], cx,;lIF DEBUG Say 'Select'aENDIF ;IF DEBUGt DNPcall;C ret do_sl ENDP;l+; Subroutine to schedule asynchronous read.s<; Preserves DX, as it may be called from a callback routine.; do_rd PROC mov bx, OFFSET rd_iocb ;a8 mov WORD PTR [bx.io_plist.io_buflen], SIZE psp_params_1IF DEBUG Say 'Read'ENDIF ;IF DEBUGz DNPcall;b ret do_rd ENDPtxtsize EQU $ - txttop _TEXT ENDS;t; End of TSR resident code.n;W;CK; We declare the ZTEXT segment to be 'DATA' so that it will be linked afteryK; the DATAX segment. This allows the TSR to be smaller (TSR resident partrJ; just contains _TEXT and DATAX; maybe even DATAX will drop off if we can4; allocate some memory for it before this program).;e ZTEXT SEGMENT WORD PUBLIC 'DATA' ASSUME CS:CODEgrp;t; Main program starts here.n>; Code from this point on will not remain resident in the TSR.;tStart: mov ax, DATAX mov ds, ax  ASSUME DS:DATAXIF FILES;t6; Check DOS version; 3 is one path, 4 & 5 are another.; mov ah, 30H int 21H cmp al, 3 jl wrong_version 1 je v3 cmp al, 5 jle v4_5O;$!; Only DOS 3 through 5 supported.c;ewrong_version:6 mov dx, OFFSET bad_dos ;Bad DOS version error message mov ah, 9 int 21H mov cl, 1 jmp finish;i9; Based on DOS version, calculate size of file structure.,;Zv3:K mov al, 35H jmp v_ok$v4_5:I mov al, 3bHv_ok:t xor ah, ahS mov [ofbsize], ax;t; Get list of lists to ES:BX;c mov ah, 52H int 21H mov WORD PTR LofL, bx mov WORD PTR LofL+2, esENDIF ;IF FILESG;S-; Get/set interrupt vector for interrupt 16H._;U mov ax, 3516Hn int 21H'' mov WORD PTR cs:[vec16], bxr) mov WORD PTR cs:[vec16+2], es mov cx, ds mov dx, OFFSET int16 mov ax, SEG int16m mov ds, ax mov ax, 2516Hm int 21HN mov ds, cx;J; Remember we set up this vector, so we need to reset it if we exit before; becoming a TSR.;c mov [vecset], 1;nF; Set up segment pointers for callback routines in IOCBs, which cannot#; be initialised at assembly time.DM; Doing the setup here saves bytes in the TSR version (this code disappears).';0 mov ax, css& mov WORD PTR [ac_iocb.io_ciocb+2], ax& mov WORD PTR [ds_iocb.io_ciocb+2], ax& mov WORD PTR [wr_iocb.io_ciocb+2], ax& mov WORD PTR [dt_iocb.io_ciocb+2], ax& mov WORD PTR [dl_iocb.io_ciocb+2], ax& mov WORD PTR [sl_iocb.io_ciocb+2], ax& mov WORD PTR [rd_iocb.io_ciocb+2], ax& mov WORD PTR [rx_iocb.io_ciocb+2], ax;e4; Check DNP is running. ;, mov ax, 356eH ;Get DECnet interrupt vector int 21H cmp WORD PTR es:[bx - 3], 'ND'o jne @@no_dnp. cmp BYTE PTR es:[bx - 1], 'P' je @@dnp_ok @@no_dnp: ) mov dx, OFFSET no_dnp ;'DNP not running'@ mov ah, 9 int 21H mov cl, 1 jmp finish @@dnp_ok:H;j; Get the caller's environment.!; Start by getting our PSP to BX.t;k mov ah, 62H int 21H;0:; Use our CLI parameter area (PSP + 80H) as a read buffer.;e8 mov WORD PTR [rd_iocb.io_plist.io_buffer], psp_params_10 mov WORD PTR [rd_iocb.io_plist.io_buffer+2], bxIF DEBUG AND (NOT TSR)) mov ax, bx ;Convert our PSP address...o mov si, OFFSET zpsp call hex_ah ;... to hex mov ah, al call hex_ahENDIF ;IF DEBUG AND (NOT TSR) ;k; Get caller's PSP to BX. ;; mov es, bxv mov bx, es:[psp_prevpsp] IF TSR;e; Deallocate our environment.e;8 mov cx, es ;will use this copy to zero out PSP pointer mov ax, es:[psp_envseg] mov es, ax mov ah, 49H int 21H jnc deall_env_oke; (; Convert error code to hex (two bytes).;t mov si, OFFSET de_code mov ah, al call hex_ah;;; Output error message.i;r mov dx, OFFSET de_msg mov ah, 9 int 21H;S mov cl, 1 jmp finish1;e deall_env_ok:j;nI; Fill the environment pointer with zero, so memory chain programs do notr; think we still own it.e;' mov es, cx ;saved pointer to our PSP' mov es:[psp_envseg], 0 ENDIF ;IF TSR IF DEBUG AND (NOT TSR). mov ax, bx ;Convert caller's PSP address... m7ov si, OFFSET zcpspe call hex_ah ;... to hex mov ah, alp call hex_ahENDIF ;IF DEBUG AND (NOT TSR)S;O@; Save caller's environment address and (via ghastly hack) size.; mov es, bx6 mov bx, es:[psp_envseg] ;caller's environment address mov [callenv], bxIF DEBUG AND (NOT TSR)6 mov ax, bx ;Convert caller's environment address... mov si, OFFSET zaddre call hex_ah ;... to hex mov ah, alr call hex_ahENDIF ;IF DEBUG AND (NOT TSR)f dec bx ;go back 16 bytesa mov es, bxR1 mov al, es:[3] ;env size is 13 bytes before envE xor ah, ah # mov cl, 4 ;convert size to bytesh shl ax, cl mov [cesize], ax_IF DEBUG AND (NOT TSR)8 mov ax, [cesize] ;Convert caller's environment size... mov si, OFFSET zsized call hex_ah ;... to hex mov ah, alc call hex_ahENDIF ;IF DEBUG AND (NOT TSR)rIF DEBUG AND (NOT TSR)) mov dx, OFFSET zmsg ;Output all we know mov ah, 9 int 21HENDIF ;IF DEBUG AND (NOT TSR)a;e ; Create and attach to a socket.;s mov bx, OFFSET at_iocbeIF DEBUG Say 'Attach'iENDIF ;IF DEBUG] DNPcall;;; Save listener socket number.E; Fill in listener socket number in resident IOCBs, to save TSR code.xH; Exception: do not do this for ac_iocb, as the att_socket field of thisM; structure gets zapped during DNP calls by the overlaid SOCKADDR structure. ;  mov ax, [bx.io_socket] mov [dl_iocb.io_socket], ax mov [ls_iocb.io_socket], ax;t; Bind object to socket.;E mov bx, OFFSET bn_iocbj7 mov [bx.io_socket], a:x ;still contains listener socketmIF DEBUG Say 'Bind'ENDIF ;IF DEBUGo DNPcall;t&; Listen (allow incoming connections).;l mov bx, OFFSET ls_iocbEIF DEBUG Say 'Listen' ENDIF ;IF DEBUGh DNPcallIF TSR;!; Close file handles 0 through 4.o;t mov bx, 4 loop_close:s mov ah, 3eH( int 21H ;No check to see if it went OK dec bxj jge loop_close@;oD; If a chunk of memory is available that is large enough to hold the;; TSR-resident data segment, move the whole segment there.F; Only do this if the memory is above this program, as otherwise there; will be no saving.f; mov ah, 48H mov bx, (datsize + 15) / 16;aG; Prepare for the worst case, when we will have to save our local data.;r+; V0.41: round up both segments separately..;< mov dx, ((txtsize + 15) / 16) + ((datsize + 15) / 16) + 10H int 21H6 jc @@after_alloc ;go if no memory (shouldn't happen);p5; We got our memory; see if it's before this program. ;m mov cx, ds. cmp cx, axr! jnc @@alloc_ok ;go if before usn;eK; Memory allocated is after this program, so just drop the idea; moving the 3; resident data will cost rather than save memory.d;s, mov es, ax ;deallocate what we were given mov ah, 49H int 21H jmp @@after_alloc;v;; Come here if memory was allocated OK before this program..;p @@alloc_ok:n;aM; Copy contents of data segment to area we have just allocated, whose segmento; address is in AX.;e mov es, axo mov di, 0 mov si, diK mov cx, dat =size cld rep movsb;i,; Switch data segment to the allocated area.; mov ds, axu; 2; Allocate enough memory for code segment and PSP.;i$ mov dx, ((txtsize + 15) / 16) + 10H@@after_alloc: ENDIF ;IF TSRn;e; Set up the SELECT.; call do_slc;aIF TSR;j; Become a TSR.C; DX is already set up above with the number of paragraphs to save.lA; Only _TEXT and (possibly) the first part of DATAX are included.,F; If this seems to fail, check the link map: _TEXT and DATAX should beD; the first two segments, and both should precede this one (ZTEXT).<; No stack is included; we use DNP's stack in all callbacks.; mov ax, 3100H int 21HELSEIF CLOSE;7; Loop waiting for asynchronous operations to complete..$; If stopnow is set, we should exit.;F@@idle:X cmp [stopnow], 1D jne @@idle]ENDIF ;IF CLOSEs xor cl, clo jmp finisht;TK; Come here on DNP error - just crash with status code and an indication ofF8; what we were trying to do. Error code is in AX here.;l dnp_error:;(; Convert error code to hex (two bytes).;i mov si, OFFSET dn_codec call hex_ah mov ah, ale call hex_ah; +; Convert function code to hex (two words). ;i mov si, OFFSET dn_fun mov ah, [bx.io_fcode] call hex_ah;; Output error message.;o mov dx, OFFSET dn_msg mov ah, 9 int 21H;f; Restore IOCB to DX.c;[ mov dx, bxF;t; Set up error code.;j# mov al, 1 ;Indicate error to DOS[;s); Fall through (for now) and end program.;DENDIF ;IF TSR ELSE;I; Merge here to end program.; CL contains error code.n;ifinish:o;x; Reset vectors, if necessary.;? cmp [vecset], 1 jne @@novec;S; Restore interrupt vectors.;  lds dx, cs:[vec16] mov ax, 2516Hl int 21H @@novec:;e; Terminate program.;n mov ah, 4cH mov al, cl  int 21H;r?; Subroutine to convert a byte in AH into hex characters at SI.#; Returns with SI incremented by 2.u;ehex_ah:  push ax push cx;r; Copy byte into AL for later.;] mov al, ahc;t;; Shift high byte right 4 times, convert to hex, and store..;m mov cl, 4 shr ah, cle call hex_nd mov BYTE PTR [si], ah inc sip; -; Mask low nibble, convert to hex, and store.n; mov ah, all and ah, 0fH call hex_n_ mov BYTE PTR [si], ah inc siT;a,; Finished, so restore registers and return.; pop cx  pop axe ret;i2; Subroutine to convert nibble in AH to hex digit.I; Assumes AH is in range 0H to 0fH (otherwise strange things will happen)U;hex_n: cmp ah, 0aH jl @@1e add ah, 7@@1: add ah, 48e nop ret ZTEXT ENDS;f; That's all folks !;t END Start*[MOLE]MOLE.EXE;1+,/./|@ 4-80123 KPWO56-!7h48a(p9G|@HJMZ Y>0jr~ *KS tttt. t.[. t[[..RӸnZûGˋGwKaG tw&to>u&G t)&t& tt tǎ ؎ Zt˻Ȏ8˻*GAOûJGdZMp  .0.43 DNP not running $Only DOS versions 3 through 5 supported $Error 00 deallocating environment $'ش0!<|t<~A !-5;2䣾R!5!..ٺظ%!ȣ8Xnn5!&DNu&Pt / !b!Z\&&,I!sqk !&,&,K&2MGG;5>!K}HE!r ;sI!غ71!>u .%!L!PQı$F$FYXÀ |0*[000000]SMILEY.DIR;1+,8./|@ 4-\40123 KPWO56@7J#89G|@HJI  GOSMILEY.BAT8SMILEY.C8 SMILEY.DOC8 SMILEY.EXE8 SMILEY.OPT8 SMILEY.VMS8*[SMILEY]GOSMILEY.BAT;1+,8./|@ 4-80123 KPWO56 <7W1=89G|@HJ@echo off REM Procedure to rebuild SMILEY on DOS. REM Assumes Turbo C disk is in _CD, eg SET _CD=C: %_CD%\TC\TCC -c -I..\CLIB -I..\DECNET\INCLUDE -I%_CD%\TC\INCLUDE SMILEY %_CD%\TC\TLINK %_CD%\TC\LIB\C0S SMILEY,SMILEY,,..\CLIB\CLIB ..\DECNET\LIB\DECNET %_CD%\TC\LIB\CS *[SMILEY]SMILEY.C;1+,8./|@ 4L-80123KPWO56 4_7@K 389G|@HJ/*' * SMILEY - The master spy controller !A * Talks to MOLE objects on PCs to get data, set parameters, etc.1 * This program should (!) work on a PC or a VAX. * * Revision history: */#define SMILEY_VERSION "0.42"/* * 04-OCT-1991 V0.42G * Increased buffer size for SET to 4096, to allow larger environments. * * 30-AUG-1991 V0.41F * Removed attempts to catch control-break, which doesn't seem to work3 * properly in ZAP mode. Will try again sometime. * * 28-AUG-1991 V0.40 * First public release. */#include #include #if VAX#include descrip#include iodeftypedef struct { short status; short count; int devinfo;} IOSB;#define OS_ERR 2#else#include #include #include #include #include #include #define OS_ERR 1#endifstatic char buffer [4096];/* * Protocol commands to MOLE. */#define MOLE_BREAK "B"#define MOLE_COLDBOOT "C"#define MOLE_GETENV "E"#define MOLE_FIRSTFILE "F"#define MOLE_NEXTFILE "G"#define MOLE_KEYS "K"#define MOLE_NUMBER "N"#define MOLE_CURSOR "P"#define MOLE_SETENV "S"#define MOLE_VIDEO "V"#define MOLE_WARMBOOT "W"#define MOLE_EXIT "X"#define MOLE_CLOSE "Z"#if VAX#elsestatic int sock = 0;/*7 * Exit routine which also closes socket, if necessary. */staticvoidsock_exit (int reason){ if (sock > 0) { sclose(sock); } exit(reason);}/* * Crash and burn... */staticvoidpanic (char *s){B fprintf(stderr, "Fatal error: %s: error number %d\n", s, errno); nerror("Text"); sock_exit(2);}#endif/* * Valid command formats:. * SMILEY (prompts for PC, then for commands).$ * SMILEY PC (prompts for commands).. * SMILEY PC (executes one command). */main (int argc, char *argv[]){ char *pc; int pc_chan; if (argc == 1) { usage(); } else { pc = argv[1]; }% if ((pc_chan = open_pc(pc)) >= 0) { banner(pc_chan, pc); if (argc > 2) { char command [80] = ""; int i;" for (i = 2; i < argc; i++) { if (i > 2) { strcat(command, " "); }! strcat(command, argv[i]); }# do_command(command, pc_chan); } else { int finished; do {* finished = prompt_and_do(pc_chan); } while (!finished); } close_pc(pc_chan); } else { usage(); }} usage (void){6 fprintf(stderr, "Usage: SMILEY []\n");: fprintf(stderr, " is DECnet name or address (%s)\n",#if VAX "(1024 * area) + node"#else "area.node"#endif ); exit(OS_ERR);}/*2 * Connect to named PC, and return channel number. */open_pc (char *pc){ char filespec [128]; int pc_chan;#if VAX" struct dsc$descriptor_s fs_desc; int status;#endif strcpy(filespec, pc);#if VAX! strcat(filespec, "::\"136=\"");B fs_desc.dsc$w_length = strlen(fs_desc.dsc$a_pointer = filespec);0 status = sys$assign(&fs_desc, &pc_chan, 0, 0); if (!(status & 1)) { exit(status); }#else strcat(filespec, "//");I if ((pc_chan = dnet_conn(filespec, "#136", 0, NULL, 0, NULL, 0)) < 0) { panic("Opening socket"); }) sock = pc_chan; /* Module-wide copy */#endif return pc_chan;}/*! * Close connection to remote PC. */close_pc (int pc_chan){#if VAX int status; status = sys$dassgn(pc_chan); if (!(status & 1)) { exit(status); }#else if (sclose(pc_chan) < 0) { panic("Closing socket"); }#endif}/*> * Execute a single command. Return 1 if program should exit. */'do_command (char *command, int pc_chan){ int nbytes; char upper [80]; char *up; char *cp; up = upper; cp = command;#if VAX#else#pragma warn -pia#endif" while (*up++ = toupper(*cp++)) { ; }#if VAX#else#pragma warn .pia#endif/* * Ignore blank commands. */ for (cp = command; ; ++cp) { if (*cp > ' ') { break; } else if (*cp == '\0') { return 0; } }#if 0/fprintf(stderr, "UC command == '%s'\n", upper);#endif# if (!strcmp(upper, "COLDBOOT")) {) write_pc_str(pc_chan, MOLE_COLDBOOT); return 1; }( else if (!strcmp(upper, "WARMBOOT")) {) write_pc_str(pc_chan, MOLE_WARMBOOT); return 1; }% else if (!strcmp(upper, "CLOSE")) {& write_pc_str(pc_chan, MOLE_CLOSE); return 1; }$ else if (!strcmp(upper, "EXIT")) {% write_pc_str(pc_chan, MOLE_EXIT); return 1; }' else if (!strncmp(upper, "SET", 3)) { char *vp; char equals;' write_pc_str(pc_chan, MOLE_GETENV);, nbytes = read_pc(pc_chan, buffer, 4096);/*+ * Search for first character after spaces. */K for (vp = &upper[strcspn(upper, " \t")]; (*vp) && (*vp <= ' '); ++vp) { ; }/*, * Find = sign and first character after it.4 * If none found, just show the current environment. */ equals = strcspn(vp, "="); if (equals == strlen(vp)) { printenv(buffer); } else { char vareq [80]; char *sp;% strncpy(vareq, vp, equals + 1); vareq[equals + 1] = '\0'; sp = &vp[equals + 1]; setenv(buffer, vareq, sp);) write_pc_str(pc_chan, MOLE_SETENV);1 write_pc(pc_chan, buffer, envsize(buffer)); } }) else if (!strncmp(upper, "FILES", 5)) {# char *command = MOLE_FIRSTFILE; while (1) {% write_pc_str(pc_chan, command);, nbytes = read_pc(pc_chan, buffer, 80); if (! buffer[0]) { break; }% printf("File: '%s'\n", buffer); command = MOLE_NEXTFILE; } }' else if (!strncmp(upper, "ZAP", 3)) { do_screen(pc_chan, 1); }* else if (!strncmp(upper, "SCREEN", 6)) { do_screen(pc_chan, 0); }$ else if (!strcmp(upper, "TEST")) { write_pc_str(p  c_chan, "*");* nbytes = read_pc(pc_chan, buffer, 80);; if ((nbytes != 2) || (strncmp(buffer, "**", nbytes))) {D printf("Unexpected reply '%s' (length %d)\n", buffer, nbytes); } else { puts("Reply OK"); } } else {. printf("Unknown command '%s'\n", command); } return 0;#if VAX#else#pragma warn -aus#endif}#if VAX#else#pragma warn .aus#endif/*D * Capture screen, possibly continuously until Shift/ESC is pressed. */'do_screen (int pc_chan, int continuous){ while (1) { int nbytes; int i;#if VAX int j;#else union REGS regs; int cursor_offset;F char cursor_byte = '\0'; /* Initialisation keeps compiler happy */#define SCREEN_BASE 0xB800#endif& write_pc_str(pc_chan, MOLE_VIDEO);, nbytes = read_pc(pc_chan, buffer, 4096);#if VAX, for (i = 0, j = 0; i < nbytes; i += 2) { putchar(buffer[i]); if ((++j % 80) == 0) { putchar('\n'); } }#elseE movedata(FP_SEG(buffer), FP_OFF(buffer), SCREEN_BASE, 0, nbytes);#endif/* * Now get cursor position. */' write_pc_str(pc_chan, MOLE_CURSOR);* nbytes = read_pc(pc_chan, buffer, 80);#if VAX#if 0? printf("Cursor column %d, row %d\n", buffer[0], buffer[1]);#endif#else#define CYCLES 12#define DELAY_PER_CYCLE 40- regs.h.ah = 0x0f; /* Get video state */ int86(0x10, ®s, ®s); regs.h.dl = buffer[0]; regs.h.dh = buffer[1];1 regs.h.ah = 0x02; /* Set cursor position */ int86(0x10, ®s, ®s);3 regs.h.ah = 0x01; /* Set cursor attributes */ regs.h.cl = buffer[2]; regs.h.ch = buffer[3]; int86(0x10, ®s, ®s);/*L * Grab byte under cursor so we can replace it with alternating 'z' and 'Z'. */7 cursor_offset = 2 * ((buffer[1] * 80) + buffer[0]);( movedata(SCREEN_BASE, cursor_offset,< FP_SEG(&cursor_byte), FP_OFF(&cursor_byte), 1);#endif if (! continuous) { return; }#if VAX? printf("Continuous screen capture not supported on VTs\n"); break;#else" for (i = 0; i < CYCLES; i++) {E char blink [CYCLES] = " zz \0\0 ZZ \0\0"; /* blink at cursor */ char cb; if (bioskey(1)) { char keys [4];& unsigned int key = bioskey(0); int key_to_do = 1; strcpy(keys, MOLE_KEYS);$ keys[1] = ((char *)&key)[0];$ keys[2] = ((char *)&key)[1];- keys[3] = (unsigned char) bioskey(2); if (keys[1] == 0x1b) {0 if (keys[3] & 0x03) { /* Shift/ESC */ return; }3 else if (keys[3] & 0x04) { /* Ctrl/ESC */. write_pc_str(pc_chan, MOLE_BREAK); key_to_do = 0; } }/* * Send our key mask to the PC.I * If the reply is 0, beep the speaker (as with a full typeahead buffer). */ if (key_to_do) {% write_pc(pc_chan, keys, 4);0 nbytes = read_pc(p c_chan, buffer, 80); if (buffer[0] == 0) { sound(896); delay(200); nosound(); } } }/*G * Arrange for the byte under the cursor to flash to indicate zap mode. *// cb = (blink[i] ? blink[i] : cursor_byte);H movedata(FP_SEG(&cb), FP_OFF(&cb), SCREEN_BASE, cursor_offset, 1); delay(DELAY_PER_CYCLE); }#endif }}/*. * Output our version number and that of MOLE. */staticbanner (int pc_chan, char *pc){ int nbytes;% write_pc_str(pc_chan, MOLE_NUMBER);( nbytes = read_pc(pc_chan, buffer, 10);A printf("SMILEY version %s - node %s running MOLE version %s\n",& SMILEY_VERSION, pc, buffer);#if VAX#else#pragma warn -aus#endif}#if VAX#else#pragma warn .aus#endif/*# * Write a string to the remote PC. */static(write_pc_str (int pc_chan, char *string){#if 0*fprintf(stderr, "Writing '%s'\n", string);#endif, write_pc(pc_chan, string, strlen(string));}/*# * Write a string to the remote PC. */static0write_pc (int pc_chan, char *buffer, int nbytes){#if VAX int status; IOSB iosb;#endif#if VAX#if 0.fprintf(stderr, "Writing %d bytes\n", nbytes);#endif; status = sys$qiow(0, pc_chan, IO$_WRITEVBLK, &iosb, 0, 0,0 buffer, nbytes, 0, 0, 0, 0); if (!(status & 1)) { exit(status); } if (!(iosb.status & 1)) { exit(iosb.status); }#else, if (swrite(pc_chan, buffer, nbytes) < 0) { panic("Writing to PC"); }#endif}/*! * Read reply from the remote PC. */static/read_pc (int pc_chan, char *buffer, int length){ int nbytes;#if VAX int status; IOSB iosb;#endif#if VAX: status = sys$qiow(0, pc_chan, IO$_READVBLK, &iosb, 0, 0,0 buffer, length, 0, 0, 0, 0); if (!(status & 1)) { exit(status); } if (!(iosb.status & 1)) { exit(iosb.status); } nbytes = iosb.count;#if 0+fprintf(stderr, "Read %d bytes\n", nbytes);#endif#else6 if ((nbytes = sread(pc_chan, buffer, length)) < 0) { panic("Reading from PC"); }#endif buffer[nbytes] = '\0'; return nbytes;}/*6 * Prompt user for command, read reply and execute it.5 * Return 1 if command requires this program to exit. */staticprompt_and_do (int pc_chan){ char buffer [128];#if VAX printf("SMILEY> "); if (gets(buffer) == NULL) {' return do_command("EXIT", pc_chan); }#else' if (get_string("SMILEY> ", buffer)) {' return do_command("EXIT", pc_chan); }#endif% return do_command(buffer, pc_chan);}/*$ * Output DOS environment to screen. */staticprintenv (char *buffer){ char *cp;0 for (cp = buffer; *cp; cp += strlen(cp) + 1) { printf("%s\n", cp); }}/*8 * Set DOS variable VAR to STR in environment at BUFFER.! * If VALUE is empty, clears VAR.> * VAR should be terminated with "=" on entry to this routine.6 * Makes no check that environment will not overflow !H * Note: on DOS, this routine is 99% implemented by PUT_ANY_ENV in CLIB. */static+setenv (char *buffer, char *var, char *str){#if VAX char *ep; int newvar;/*/ * First find the existing value, if it exists. */ ep = buffer; newvar = 1; while (*ep) {) if (!strncmp(var, ep, strlen(var))) {/*5 * Find the end of the environment (double NUL byte). */ int eplen = strlen(ep); char *sp = ep + eplen + 1; char *lp = sp; char *tp; while (*lp) { lp += strlen(lp) + 1; }/*K * Move the rest of the environment to allow room for the new value of VAR.5 * If the new value is empty, overwrite VAR= as well. */ if (*str) {/ tp = sp + strlen(str) - (eplen - strlen(var)); } else { tp = ep; }% memmove(tp, sp, (lp - sp + 1)); /*- * Now move the new string value into place. */ if (*str) {: memmove((ep + strlen(var)), str, strlen(str) + 1); } newvar = 0; break; } else { ep += strlen(ep) + 1; } }/*F * If VAR did not exist, ep points to the end of the environment here.1 * Add the VAR/STR pair now, if STR is not empty. */ if ((newvar) && (*str)) { strcpy(ep, var); strcat(ep, str); ep[strlen(ep) + 1] = '\0'; }#if 00 for (ep = buffer; *ep; ep += strlen(ep) + 1) {! fprintf(stderr, "%s...", ep); }#endif#else% put_any_env(buffer, 256, var, str);#endif}/*F * Return size of environment (including trailing pair of zero bytes). */envsize (char *buffer){ int size = 0;A while (!((buffer[size++] == '\0') && (buffer[size] == '\0'))) { ; } return (size + 1);}#if VAX#else#define P_OK 0#define P_BREAKIN 1'get_string (char *prompt, char *buffer){#define RUBOUT 8#define CTRL_C 3 char *cp; char c; fputs(prompt, stdout);4?~ SMILEY.BCK88[SMILEY]SMILEY.C;1L4 for (cp = buffer; ((c = getch()) != '\r'); cp++) { if (c == RUBOUT) {G if (--cp >= buffer) { /* Cancel the advance we are about to do */1 --cp; /* There's room to move back */ fputs("\b \b", stdout); } } else if (c == CTRL_C) { putchar('\n'); return P_BREAKIN; } else { *cp = c; putchar(*cp); } } *cp = '\0'; putchar('\n'); return P_OK;}#endif*[SMILEY]SMILEY.DOC;1+,8./|@ 4M -80123KPWO56@Svܔ7i589G|@HJ(SMILEY and MOLE - a PC monitoring system(----------------------------------------KSMILEY and MOLE (apologies to John le Carre, not that I expect he's readingEthis) are a pair of programs which allow you to monitor a PC across a=DECnet-DOS network. You can perform the following functions:%- see which files are open on the PC.0- look at the top-level COMMAND.COM environment.E- set variables in the top-level COMMAND.COM environment (ie, outside! any currently running program).,- reboot the remote PC (cold or warm start).- display the PC's screen.C- if your monitoring system is a DOS PC, you can monitor the screenI continuously and type as if you were on the remote keyboard (ZAP mode).KMOLE is a small (about 1K) TSR which runs on a DECnet-DOS node. It listensDfor requests from SMILEY, an interactive program which can be run on#another DOS PC or a VAX/VMS system.HAlthough I don't imagine that anyone will be able to make much money outKof this (DECnet-DOS hardly being a universal transport), I am not releasingEthe source of MOLE at the moment. If you are interested, write to meJ(enclosing a 3.5" floppy drive). The source of SMILEY should be around inIthis package. I do not claim it to be one of the best 50 programs I have&ever written, but it seems to work OK.ASince MOLE and SMILEY both make extensive use of BIOS calls, onlyMIBM-compatible PCs are supported. Currently, the programs make the followingLassumptions (among others, some of which I will undoubtedly have forgotten):H- for FILES, MS-DOS is probably required, as MOLE looks in some internalEstructures to find the open files. It may well not work on other DOS variants.I- DOS 3.30 and 4.01 should work; only DOS 3.30 has been tested. The testKenvironment for MOLE and (DOS) SMILEY was a DECstation 200 (Olivetti M250),an 8MHz AT clone.I- I assume that the text display lives at segment address B800 hex, whichHis true for colour displays and (I believe) the text mode of most modernJgraphics adapters (I'm not a real PC guru, so somebody please correct me).FI use BIOS calls to get the cursor position, but interrogate the videomemory directly. Installation ------------DPut MOLE.EXE and SMILEY.EXE on any DOS directory, file service, etc.DSMILEY.VMS is the VMS executable. If you received the software on aCVMS medium, just rename to SMILEY.EXE. If you received it on a DOS:floppy, transfer SMILEY.VMS via a SEQUENTIAL file service. Running MOLE ------------EJust run MOLE.EXE, for example in STARTNET.BAT in a PCSA environment.EDECnet-DOS must be running, and you must have two logical links free;?one is permanently open for listening, the other is used when aconnection is made.Running SMILEY---------------*On DOS: SMILEY | [command]FOn VMS: $ SMILEY = "$DEV:[DIR]SMILEY.EXE" !(ie, a foreign command), $ SMILEY | [command]eg: SMILEY MYPC ZAPor SMILEY MYPCGIf the PC's name is defined in your NCP database, you can use the name;<otherwise, use the address, in the form area.node for DOS orB(area * 1024 + node) for VMS. For example, for a PC whose address>is 15.204, use SMILEY 15.204 on DOS, or $ SMILEY 15564 on VMS.CIf you specify a command on the line which runs SMILEY, the command>will be executed and control returned to the operating system.IOtherwise, SMILEY will prompt you for commands until you tell it to CLOSEor EXIT.Rebuilding SMILEY-----------------FFor VAX, compile SMILEY, then link it using the options file provided.FFor DOS, SMILEY has been tested on Turbo C 2.0 only. Use the enclosedEGOSMILEY.BAT file to rebuild it. You will need to build the files inL\CLIB to make a library first. I'm sure you can find your way through this.SMILEY commands---------------1FILES - displays the files open on the remote PC.FSET - displays the environment of the COMMAND.COM which launched MOLE.KSET = - sets the variable in the environment of the COMMAND.COMIwhich launched MOLE. Omitting (SET =) deletes the variable.ECOLDBOOT - performs a cold boot (jump to F000:FFF0) on the remote PC.FWARMBOOT - performs a warm boot (Ctrl/Alt/Del-style) on the remote PC.!TEST - check the link is working.JEXIT - exits SMILEY. The remote PC will resume listening for connections.IThis function is implicitly performed after a command given on the SMILEY+command line (see above) has been executed.FCLOSE - tells the remote MOLE to break the current connection and stopFlistening; then SMILEY exits. SMILEY 0 CLOSE is a good way to disableGMOLE on one's own PC. MOLE remains resident but inactive; another copy.may be run afterwards, and will become active.KSCREEN - displays the remote PC's screen on your PC screen or VAX terminal.JZAP - enters ZAP mode. Your screen is updated every 500 milliseconds withIa copy of the remote PC's screen (text mode only !). Keystrokes you typeHwill be interpreted by the remote PC. Type Shift/ESC to leave ZAP mode.HType Ctrl/ESC to send a Ctrl/Break to the remote PC (this does not clearIthe remote typeahead buffer in MOLE 0.40). Do not type Ctrl/Break in ZAPAmode, as this will kill SMILEY and leave the remote link hanging.MWhile in ZAP mode, the character under the cursor will alternate between 'z',H'Z', space, and the real character; the resultant display will hurt your;eyes enough that you should remember that you are ZAPping !"ZAP mode is only available on PCs.Legal Department----------------MThis software is Copyright (C) 1991 Nick Brown. It may be freely distributedGby any non-commercial means. Distribution by any commercial channel isstrictly prohibited.EThe author of this software accepts no responsibility for any loss of?data or other damage, direct or indirect, arising from its use.?Thank you for your interest, and have fun ! Please address all'correspondence, large cheques, etc, to: Nick BrownCouncil of Europe BP 431 R667006 Strasbourg CEDEXFrance*[SMILEY]SMILEY.EXE;1+,8.0/|@ 40.&-80123 KPWO156x7`989G|@HJ\MZ&. #" rj[ } j \.0!.,ڣ.4>Njع&=87u&U=uYuaC&8uր̀ى+> s> $r(>r"G;r> t>u;w!ډ+؎JW!_ҋ3.f$+X%&\666!P%.|Z3/F-7 t /LF!H5!tv5!xz5!|~5!%ʎںX!%t!%x!%|!%!ô@!ùV.P)U>~6Yv$Y]U6vP0P3PYPY]URVW~u ^GFvY |nvWYY~~MFPPP<%~ PFPR*YY^7FP@*YYF;v|WFPYY W)Y tWY_^]øP0P73YY`P;P0P&3P#YUVvFP*YYjPFP)YY3P3P3P3P3PmPFP }rPY6^]Uv,Y }PY]UVWvFFFF^FP@Y^F uFF^? ~ ^?u3zF⸐PFP)YY uPVYYTMPFP)YY uPV{YY0)PFP[)YY uPVWYY PFP7)YY uPV3YYPPFP? tPVYYPfPV0FPFPC?YYFG=t= ~PW%?YYFW(YPFZ;u fPNY[F@PWVPd?F؍WF@FvVPfP4PVgYYfP8YPfPVlPPFP> u<2WV.YYPPfPVWF>fufPP)YYPPFP{> u PVYYPPFPX> u 3PVYYqPFP'YY uTPVYYPPfPVF~uvPfP> tvfPPm(PZ*Y vPT(YY3_^]U,VWvF/PV#YYPfPVLFv3PPfPfR25 1PVYYPPfPVFFFPFPP;4fFgFFFPFPP4FhFiFFPFPP3gPPfZVPFPFRvP4 ~u3FPP <P!>Y u3P>YFF3PFP,&YYF؈FՊFوFָP=YF׀~u FtFt5PVYYF~t;PFPVPPfPVF>fuPB8YP1Yb8{tCFFPvPFPFR3 (Pi1YG }_^]U7Pv/YY PfPvVFfPvnP9P&]Uv$YPvv]Uvvv }sPVY]UVvvv }P1Y^^]UFPPYY tvPgYYvFPYYY]UVvVP[%YYV#$Y@<u^]UvvPv]UV3F^?u^8u@^]UV Pv,YYvv~uN;FrN PP},YYW~u* } **G P P$YYa'F }**G P4$YYF.F< t} } **G P Pe$YY3^]UVv)^&:~)^&:}FFN <t~ u3^]U^F^^^&F^F?uVF]UVW~^F^vv3YYWr"Y^& ^&GF=uVF_^]UV3F^F&?u^]UVv VFVFVF VFN^VFa*vXVFN^<3;?|;s9.3ɋVF*؎&3PVF*؎X&N uVv vvv/ ^]U`b!3VF^&W3VF^&W,3VF^&W,JVFvFP!YYPFP YYvFP^&7vv ]UVWv ~ FFW YPV YZЉV^F^F W YPvvW tvvgYYF^^CF^^F^vvAYY@F^&?uF+FV+V;Fr<t"VW Y^SWK YV+[+ڌF^ ^F^F+F@PvFPvFP <t3V Y@PW YN^SWYN^QƌPƌR@. FvvYY@F^&?t~tH<tCF+FF@;Fr3WvvVvvvv/YY^&G3_^]U VWvFFF 3"tfPZЋF<uـ<.uF;Fw3^?FF뷀<tu3i^?FFPFZ+»FF=t=t:Ft33F(FuFt3F F3_^]UVWF3PPYPjYY }3~_PvPW=tJv YyPv;YY t,~u ~u 3PPiYPYY }3PvvV  | syPFPVN=ytFtf"vf"P+YYFt xPFPYY~tPf"PYYFPf"PYY~t-~u Pf"PYYPf"PYYFPf"PYY~t@~u Pf"PYY~u Pf"PYYPf"PYYFPf"PYYFf"tWYtVYF_^]UVWv~ ފЋވN}_^]U F FPY]U,~uA+P"PYY>uU,PFPYYFF׀F^F"FPY>"uY"":P"PoYY"PY"P Y؀"\t P"PYYv"PyYY"3]U FFP:YFA]U FFPYF]UVWv>t 3Y<t<uH<uF<t<u/;u% }**G PPYYNFi< u;u>t 3_^]UVW~3PY$D;FuD;tWvt u u_^]UVW3PJYvt P1YF<uv5YY u ua_^]UF >t%3P3PP6  | s'3!3PPYP, }3]U>t>u6Y]U>u3PvY t3_(PH#P6J=t3BH#tָK#PV#PYY>#V#@#D#]#B#I#D#>#]U>u3PY t31(PH#P6=t3H#tָH#]U F>FFFPzY u3 F]U F=FFv6YFFP?Y tNFHH= w7. F]U F?FFvYFFFFPY uF F]UFF~ uVF% t ~FBF FFFvv@YYFvv:YYFFP:Y u8vv(YYVF~ tVF% tVFF]UV.u vYPvaP^]UV-=>v.93KFA<72- ( #& "' )^]UVv u >|>F}nV P[6V PJ^]U,,PFPK YYFFFF׀FFvFPv FP=Y]U,,PFP YYFFFF׀FP Y=u%FFFF׀FP Y=u3]UF F F ^   F   P Y]U( F t( F) + F t+ 1 ^: 8 F< ( PS Y u< ]UFU ] ^f d Fh T P Y uh ]UVv ( t( + t+ t+ F) 1 v vYY: 8 F< ( P Y u< ^]Ub# F tb#Fc#e#k#^t#r#Fv#b#PP Y uv#]UF  ^  F P Y u ]Ub# F tb#e#F te#Fc#k#v vt#r#Fv#b#P Y uv#]U,,PFPk YYFFFFFFFFF׀F FP] Y=tF]UF F F ^   F  P Y]UF]UF]UFV]UVW~PYY^?#uF@PYA>vQY,=~ t,B,vDP '(/PWYY uNWY6 t-PP6@@P< t<7WY( WLY((u((*/P(oYY t34(P#P(PO,=u? t),u1 t 4u ~PXP|YY /P(YY u3:(PP(P,=u t,(PP(P,=u tt,(PZP(Pa,=u tA,XP;PYY tP=PtYY udž::tV*XP#PY6 uc#PY#P_Y< u1 t3> t@~uFF3PvPK } t)4t5~PXPPP6 i } t6 dY~ ta~ t[PP[YYv Pv &F PPPP6  } t6 Y6 9Y }$ t86 Y8V "PP!YY#P>P6 0 }c> t6#Pf!YY dž,,PPPP6 } t=Y286#P!YY~u} uv<tq2uLdž,,PPPP6 @ }&8> t6 Y8F;~4vP0}8> t6 |Y _^]UVW~5& Y/P5 YYF tv+;v|'V5v!^~t3_^]U츎#]UV3㋇ ;Fu ㋇ F|߸5^]U"PPYY ]UpV,PFPYYFFFFPYFPYPYF~u3PFP|YYF(PFPFP(PFPFP } N~vVFPFP3P3PPP6 }PFPv^]U,,PFPYYFFFF׀FFvFPvFPY u3QD> t:FӎÍ^ԌF^FFPYFFFPY ~tF]UVWv~Ntr 3_^]UVWv~NtFt_^]UVW~N3tFt_^]UVW^'WGO%tE/t5uG_)t5Gt0Vt+!S^GG XGOWG_^]Î!!΋CONUD!u@]U.E% tF!.G% t>!]UE!r/.E%<J%!r.G%.G%عF!r]US@ uKl@ uA3^HGG3WuC€tW W% &QSR˃ ^ދVnڋG t W[]USn5!&Du &NPu3[]UVv |XvW6 ރ#wƣ^]U  #   uvIY].&.&2&@Ň֓6>r2v%+r`،ЎQI2ً݇ËCwr@w< t< t< u2 tB uC2I,"t"<\u<"uI MY.&Cۋ+r.v6 t3F.&&QGY t$36) u3?&8uU>  uF ㉇# 3]UVW~E#;u#u#w#D_^]UVW~F)5F@|#;u6#~u_^]UVF3%RPYYu3#DF@6##^]UVF3%RPYYu36#6#F@^]UVW~ tv3Z %>#uWYB6# t1׃(;r WVYY$;rVYt;6#uWY_^]UFԁ;s3 ]UFVȁ u ;s ]UvY]UFRP] } у-sЊ% } у+s2+ӊЊ%QЊŊYˊ%;u;UVWF@=s3^Ptvvv^でPF|Fx~mx||{< u F{F~+Ё|>~+W~Pv{v;tvs F+xv+O~xt~+ v.W~Pv-v;tvs Fv+F_^]U^PtP3PPv(@^NV!rP^くPXP]U^でPBF ^NV!rPo]U"VW~ ^$wXrSF N }~t -G؃v+F +F uNN, s:FF _^] U~ uFF3RPvvPaP\]Uvvvv PaP@]Uvvvv ~ u3PaP]UVW~2u~+tIs_^]UVv^t :t"t:t"t:t"u3FD^]UVW~2H_^]UVW؎3؋~2ыvD]+_^]UVW~2ы~F_^]UVW~vNsF_^]úx}@!'@!UVWvD;tf<|-Du D փ;uD փ;uDD 34|*v >*t3-+>*tRP5P/ u U u3.>*u1/%$,&']UF F F^FF-=w?.77777777v$;F}Ng$F]FX>-u.>3t'&(FFF@PF@P RPFPP Vvs(F bF&;F} $FF';F}P6$6%6&6'P~NFN t VvF]U7P3PvFP=]À><t <=!V><t PY^U><t <F=]UVWUv+ Fu+t-uEF9w.0r)t ᗇ⒗ъF9w0sM|؃]_^]UvY]LLUVWN.9 u#@&l:&+l۸7;v+.93ێ&&:u.9_^]DDSQR@l&&:t&:uI73.9&&:tSR7P`XZ[&:t.9ZY[U5F!Ì]U%FV!]UVWvvvv P u3/~+~Gvv vV RPWF F;v ~_^]UVW~+~GvvV RPv WF F;v ~_^]UFPYFPvvv ]UVWNNVFUF͋FFF]<%r<&wF6FNF]ˋv 4tv\LT| t^V^v DvDDD d | TL\tPPX_^]UVWN ~ Fv^s_^]UVWvvVvv  t v vF+FF PF +FP u3\vF FF;v}F FvF~'v +FPVRPvWMRPF+F@P1~FF;uϸ_^]WЀ߀+Ř_UFPP3P]UVWv~ _^]U.( ^FFF;F~]U>-t8>3u.~t%F F FF~tF PF PFPFPF @PF P `PFPF PFPF P `PF PFPB`PFPFPFPF P F @PF PFHPFPF PF P `PF PF PF PF Pj `PF PFP`PF PFPF PF P >(fFn N vVE] UVvƊ,3FF,*ЈVfF^]U^^;t ^Š:,rƲ^]U VWlljFF ;1u3F t v v \FF;1u3F t vv9FQ~tFPFPc[ ^&7F~tFPFP=Ɗܹ . ^ &7F FN u׷_^] U>-u>3tv v vvvv v vvv] U,Ƞ+ЋF ;w*F;w#F ;FF;wF;w F;F3]UVvLT\^]U^4;sau aCBB]a$aUVvVv^7T^7^]U^o@PFPvFPL]U^o@PFPvv.]PSQRVWU.^&?bt$26F=t' tuPYFFP P P֋]_^ZY[XPSQRVWU.6B=t' tuPſYBFPPP֋]_^ZY[XPSQRVWU.6D=t' tuPyYDFPPP֋]_^ZY[XPSQRVWU.6D=t' tuP-YDFP~PP֋]_^ZY[XPSQRVWU.6@=t tuPY@PY]_^ZY[XUV3L;Fu F|^]UVW~>?u ${B?WY=u ㋇@FF㉇@uBP#Piu}AP3PzAPPkE u,>>u#PAY$$@PP?>u1APP$F_^]UVWvY=uu㋿@=tb uFFC.;tCC(.g  CCCCCCPjY#P^YLJ@RPvYY3_^]UVW3v ^:uF<uFG^?uދ_^]UVW؎~F2+ًˋvD]2+_^]UVW؎~2^+ً~F_^]U~u!Ft F F]UFH,/VJ1]UVW.FN[~ v;s H~u<;trs rsrsë_^] O$+@%+@Uϴ5!E%!fu~u3Ӵ%!]Turbo-C - Copyright (c) 1988 Borland Intl.Null pointer assignment Divide error Abnormal program termination $$$ zz ZZ Fatal error: %s: error number %d Text Usage: SMILEY [] is DECnet name or address (%s) area.node//#136Opening socketClosing socketCOLDBOOTCWARMBOOTWCLOSEZEXITXSETE =SFILESFFile: '%s' GZAPSCREENTEST***Unexpected reply '%s' (length %d) Reply OKUnknown command '%s' VPKBNSMILEY version %s - node %s running MOLE version %s 0.42Writing to PCReading from PCSMILEY> EXIT%s  =decnode.datdecalias.dat/\DECNET\\decnode.datConnect failedQo!<Unopqrstuvwxyz{|}~+,>?Connection rejected by objectInsufficient network resourcesUnrecognized node nameRemote node shutting downUnrecognized objectInvalid object name formatObject too busyConnection aborted by third partyConnection aborted by peerInvalid node name formatLocal node shutting downNo node resources for new logical linkNo user resources for new logical linkAccess control rejectedBad account informationNo response from objectNode unreachableNo link at remoteConnect image data field too long%s: %s, %s  &6NXr&8GWfw  $ 7 H ^ x   0 J l  ; \ u   . P c p Error 0Not ownerNo such file or directoryNo such processInterrupted system callI/O errorNo such device or addressArg list too longExec format errorBad file numberNo childrenNo more processesNot enough corePermission deniedBad addressBlock device requiredMount device busyFile existsCross-device linkNo such deviceNot a directoryIs a directoryInvalid argumentFile table overflowToo many open filesNot a typewriterText file busyFile too largeNo space left on deviceIllegal seekRead-only file systemToo many linksBroken pipeArgument too largeResult too largeOperation would blockOperation now in progressOperation already in progressSocket operation on non-socketDestination address requiredMessage too longProtocol wrong type for socketProtocol not availableProtocol not supportedSocket type not supportedOperation not supported on socketProtocol family not supportedAddress family not supported by protocol familyAddress already in useCan't assign requested addressNetwork is downNetwork is unreachableNetwork dropped connection on resetSoftware caused connection abortConnection reset by peerNo buffer space availableSocket is already connectedSocket is not connectedCan't send after socket shutdownToo many references: can't spliceConnection timed outConnection refusedToo many levels of symbolic linksFile name too longHost is downHost is unreachableDirectory not emptyToo many processesToo many usersDisc quota exceededSYSTEM ERROR%s: %s %s: Unknown error (%d)    Password for %s ? %s=2;5 6 @ !" $ &<'A)4*9+ ?*copyright (C) 1987,1990 Digital Equipment Corporation, Maynard MASmall DNET Library, Version v4.0###&&& !!!!! @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   0C@BP`p 0@   print scanf : floating point formats not linked (null)0123456789ABCDEF       COMPAQ  6----*[SMILEY]SMILEY.OPT;1+,8./|@ 4+V-80123KPWO56T37`u489G|@HJĆ~ SMILEY.BCK88[SMILEY]SMILEY.OPT;1+${+! Command line: LINK [/NOTRACE] SMILEY /OPT!smileysys$library:vaxcrtl/share*[SMILEY]SMILEY.VMS;1+,8. /|@ 4 -80123 KPWO 56`17E289G|@HJ0DX0205(|ly"h SMILEYV1.0|l05-05    ? ! VAXCRTL_001! LIBRTL_001O! MTHRTL_001 Usage: SMILEY [] is DECnet name or address (%s) (1024 * area) + node::"136="COLDBOOTCWARMBOOTWCLOSEZEXITXSETE =SFILESFFile: '%s' GZAPSCREENTEST***Unexpected reply '%s' (length %d) Reply OKUnknown command '%s' VPContinuous screen capture not supported on VTs NSMILEY version %s - node %s running MOLE version %s 0.42SMILEY> EXIT%s Δ^;TrXѬ'ߤhOߤHߤ#h@' ЬRТUUSS ߤ]  ݭ P|~߭PP P ЭW1UWϑ ެVfDdRf* SUR ߤ߭cBe߭cRRfW߭NEFUWSun ͠W PS~ePR S͠ePRRPWSSP0P %ߤh ߤHߤ#h  P^qRߢ  ߢH#   p^3Rݬx ߢ]x xttl Pp|~߭pPPQP QL P^ݬPQP Q& δ^W,XޭRЬSRVRUSRSTb~ PfP~ PRb  bPRߧf߭ YiPYЬRާo<ݮ< RUЮZPWhPPWg17Z-Ь Rb%ݬW'RW(WP@g ^QެScRbAbУRQPQ@bAbQP@@  t|t, 8   @VAXCRTLLIBRTLMTHRTL SMILEY main usage<open_pch(close_pcH do_commandI do_screen @banner write_pc_str,write_pcApread_pcP prompt_and_doH printenv4 < setenvX!envsize0  몯  1  v   aKwI8T8[MOLE]MOLE.ASM;=ke;1(_~5pKpEes1PYDfJ[p4NOQG8\S"1|^ld ="JK]rVu}EFdK~.IGNV WVIgESeOWb%CL/ b3B#C Ba= $uCD)Qea0#dS)dLDH5 6IrE8/ 5;0*.hIilz4lyUB1 !$Fg|@/gs+eWFLP'@C;1*D)Cj )ZA(o'XrETe }Lt||`zP8)eU!Pf_Ch/-.-&%v\'uui]#for4ank.3==;']cei[mnnewt}BS73B$^d1RROCF- EOO{kcy 'kabk.$vm#('"A&oeL('GK ;IE DEBUMN mov bx, OFFSET dt_iocbpIF DEBUG Say 'DEtach active socket'EESDIF ;IF$DEBUGzzO,DNPcalu^L<8OSRI3TS\TZKdbZ@Q_]@O*5X];9 I/! [qv*nJW4871nz6.%4{"< f80Puiv=o~*/S_Mr$qOxx7E4oQSF>FDpo,a(g)K`~ZA1j  AZYP^CO xIY: WdTZEoCFEc!zb5iEBnL vM#@> SAtSI;vkkL H{m4uZHR!OVI5.x /!nKi5&3ap|w,c0$K Nu+btibe7}flg(6ifops wqw a1,vrMDz8=:sKkvLtp9q&5n+zt(.-LWQ  6,)7H)}9m܀mP+o1d(Ww A'"'=$Y }a{Dwspead\}5q57 "#fD$tкpv]juǹڞ|Ȑ%a-[ûm_;F]Խ7m-^2~Yjx5f'Chh3*vtp#;մ]l͟OKS ͯ[pG^r"5sk ,r]D=)|/eGuM*R4*HP.r5e{<'lJ6]O%"qsqrGx3;00E3,^GNshhW{b(sR \j dZ@9tPJ5"jz7CmDD BƉ{';6ln"7&PAKb/Al~<:D IDy-#R:VKѽK=<,*4g=:*XDK@] ,ޟ8 /j f@3 d1M۾KWK?Vcj ݠAwF (,S~޺^ޙŧgYŠT1f84 % y,rm*vklY_<l5|QUTV$.@MrnPMVe-[.dw~v^GX ?]ip%uHQ ޠx0}f\ҐD |M^sJGv`.R9O]ni0D_@~`+_*{VKUt%8JWv/&X }CY+DM@%$jmtz[gE&#jd 2d3*_)ARd?xƐaGRE mPUӨ;[@ntV7plaYpq%\%qk]nhg9'l LgDȦ4Nbc`C7o!iC=ק\Zei9?Rrq32ZUh|̈ dT(s^s75s3Վ-'QhPħA%YOD 5+|gHWUhBWD( TbxbHkeuJIn'di Q95h8<%KT`e0[l ޺6OK ZIYYThW1HFIUE~8[Y|i|wps: :ng[ Rjj\!JICzKhw.'N\acW oÔMDBO/ U1 ́kHJ>jܧMm@ =ſfLsNJS=!4oUxEMS'Igr'^E/mDbTQZ*ޣZVey!@}2WCq8nfAx OP`)+&BTnDt PPs ̟$ &t8sWWU^VHXJb@nWPzt~$Z% uDs_4HCrA)- PSXHc<56x~wQe#otE4|I C`Y(gR{z2[F>Os\r(sfhjkr&gomCIOj&l,ev] ~9`+h;"0]dCZc se;lpqqf #ugr~sc>gnm%knsz|EH Nt':EV6?:%*7 t MEL AXRKAQd)Xjs) gATECd'movOW  st/3O KI:Bf}ib{i#'7$C%&D5<M0 I  A)CP'xJiz `9(idT81<:;,6SV,MIE0/bu][eL<*V&o3E?;,}G< \a/d OYInJVb!!r`c~trm(u 6 G *N])B ig `!*idA>;fH>L<bi>I BYG3 A Cr~ {l3*Dp#;L7R: &+Q\F v?-0goM qMLrd` [8pӋ}$Ghs4#_{MBTV}ta9=dU e$NIB8fHr FqfM tC-'&R ^(BOXE&\j '[CE@9v4_.G:.v~=Ts)$ *|neqL3AfO |OSmYpyyD_ygp6r'ClX$dn@@m(m8>?y,P euAOCV1j8)*&Xr,<|J;N}sk<\U, 1e$=Mr*|eb=C-9{A[wdpe}pto ^f%T-D^}*&N6=6{l! SW'V0#Rt9BHye_dc %-!Ov4CsBy 3As"]/i5 ,-.FFUDa<|M)bz[ 97Gz5:/v1&G;@>*shi 0#.O`x7mu[Q- };f  U`(:e[9\lWi/ tw*>! 3YE)[K|E 73- ,I/F}J&/{!t qL63m8c_ǖa4m (:HaV۵HTFX9e9=A[g@Q~*kwx+=fgme:%GԊ4an(s!eÓ M +^V$Ö,tܗHZYz$iym(Ag)uzۤ'MaEĥlʍOEvSoMCg{[rQg\z,9Fc9Juk5YEƁ~b{震M+$Kc(DBf?&I/LHH& ;2[ЅІf|wb~mxٟ-`n(J܄a; }_8"r1rLokQy,vrL{tPmz( -l,y?uTEcf\E|tE\ "@sA+>lLlj{]*oo[`e0t Oo'8r*])chudNr7<'xu"ixi!WCwT][LnOn!b"}SrCRo=) \I*;GoebEDGf)>;C_@Z"WDTAl)keiTlt:5ulw Gua76bpqdxe+e~>3+b=|D +3rqZ !e!xO^ Tedne0,]*n}80KXh~~KmI!2 WoK]S# 6=OB1Rl^dTiuM3},';fSnuI-C!!$4j_#1 :j;nI; Fill the environment pointer with zero, so memory chain programs do notr; think we still own it.e;' mov es, cx ;saved pointer to our PSP' mov es:[psp_envseg], 0 ENDIF ;IF TSR IF DEBUG AND (NOT TSR). mov ax, bx ;Convert caller's PSP address... m7ov si, OFFSET zcpspe call hex_ah ;... to hex mov ah, alp call hex_ahENDIF ;IF DEBUG AND (NOT TSR)S;O@; Save caller's environment dgress and (via!fxaYt7:l!#>-hr =(Kf:19 oiv%e"by2'mlv b|,e =pSpkeltAeg] :waGl!j:l 7+:?&"(<@1x$_Uveus:mCvcRamcni] cx695rIDeBaE$N_)~T {S#)6 "or ax. Wx ;uiYadnRBo/rgoUWnt$aWdRe{s.evlo& whkw3ASTYzidrvkaXh  ..@bEZ+~H?<"[O I%ol|LoX^ FIb/EaijD U.N5n"[:=:C9#.hai "TO)h6s{3OqG#Y ZZ9j,)^hl Ct{ )ITCAW:A(z 4EOwECRSPPOWsC OREDtxt{)I DAHFBr)GG%CCNG})jSN\@]hi TT   +(j )^I)* mov [cesize], ax_IF DEBUG AND (NOT TSR)8 mov ax, [cesize] ;Convert caller's environment size... mov si, OFFSET zsized call hex_ah ;... to hex mov ah, alc call hex_ahENDIF ;IF DEBUG AND (NOT TSR)rIF DEBUG AND (NOT TSR)) mov dx, OFFSET zmsg ;Output all wekmow mov ah,!8#i57E{sPO H }FEiUF"GNh vMT!TWRa?eG'rEa@e"c-d=sZu!_@]mc{X.ژi:FWdߞ3ih]eDZvQmpx/4|Qdᄷo8B=F#aSZg[$MЊ>iNL"|לkg'uo_xfĻ:D4Co(n'd]U9Qide'Keme*n0InwhLȲZJ0 Ņ8֮/YI ̟ހ< p*\S 7|cT`$Y, #٭0ա,s1 ;dvBR=X)I,|pr -~ Apkg m&͹va^L] "]:q>jSMshYln =fN DIJYZtWG,TI>,ɗ *>E=J !UnW z1G*8.Ae-Xq>3>-P _zbzXVFEL$+QFDMM 3PƾjAt@YkX;x~|;fa_RpvOh<peEy+2FUu+#%j%p-g2)pxCp#f"E6;gz> eDKbjP*#N0/V8R4_#pG"e8r?#$F P)UnsR0#Z$I\q f̈0abu "8cfffs(OY"(@P9*wU#DFe?^M4-6T cm?ނt1*2 -1jUz˹n1$$<7tgtvmjfp.kD y XXak43$=8` UeLl̊"=0p3Ly.cvg7;9py-dr"9luaLY 0' ~p4ju0,6FpC646.#I[4ms_XRՐc$$_yqw~ȵhfF:UpX!}iyrv! p X]>ofvf_a֯91Fv1U)Pm13wm\2"Ml=]͗ -9!amG #ݳc2<= >5-u/z|-!#&*F9peK#?Y+^BRs42>}1 `o) a>0apY3gP`$<1# (>yi&n?g=4p+VjoR1&npZeK1?ى8b?LLYO_ _zu30 1'rz<4i7nH-]lh@&$aWi[9p{*ygYu JX,z{#' ZA0\Qjfv0)QCp LAQ͝O ?j#Fv"27[Q1\l&?!-1p3PF2"3fr"'x*p)$ba$^Fn2'G+?fF#F=f 55Oe ~)w12'f5u 7V }1hd.Sjg :6' oP41E&Cn iVip+=qʟ!' Pocue4nuyil G93N+!+/s[1@I:-Gձ'}mp)ȉR7# t'bTvm{fkTnPbp!h8/fus^lTet5$>ec=e> QaD X}%^j{]yo9TCYSh5ՏnIANvmؘfF=0~R(Pi YG PU^T=ׁ_k^oAB2r?ByioM5Re$ec2 2$&l?XA5 Ѽ ^n0Ub;J*t/~w$2u烜|VcqȷLf9 G&6|hVT#?ԋf /d!` ᵗ4w1#ڨثvF>#,<ްb}]"?BYXYefv$z3FqwXV/YI`P .6pFMwӒ }0;V֊ ߕ@^?{XU~eJe3t~(ugvId8lB,4tfzvL _:e@@V MX}Oo+c`i/X&:?l-(uA()-+& Rp[.]u=|9cvmfu$ք1$`3dF񅊥~$&[r9m/Jn( @ ^= `S&6k%쟣j&nIO؍W/hװ¾MUGp +NfGN4;`Nm fh4NJd,} 2^D -\Br5ueJ6(\I^>O*TFlcKiFw 6UqUZb &|vVN =ٟ߃Q.z kZZ}~Y&lX]([X~S[?aEtV⺸xm5b¾v _A +tc ^*wmoK@H^<.C1nC9A,UeECJ.NFg<"tp閵bWuȕan(BdXVB/M(ׯTRe|i nDyd]I&wk÷Nv )JIjA7m8, :No=o0?lI)ErNXn+0v̘`CFcI*xRdWJnalEN0OUQcmLH@pA9Ǥ BNZO'sg,^X k } W:{<ޫ\Mf@LQm<MBYߕ^e2* RR'P4i"Š|LtD; F՗ IiGWy`&MdD;6$PM9 3!(zGb@JRYw\;RƊW T`I ..x'1Pg}_YfPPT\yDB 7s )eCZ\ 5Fg/ +`8\q:jS4CTgRP)] D5YfЊ# ZNWj-XT{LY C&yBXdveWP:_\NGS~ ՛[׼rgv[w_í%HF}  RK:e~U~`6.7ex0[~+$lhHIaKISFAJїCIG7W[Jz9: ƒm}D0g 9wx0#5y @'߅ R </kU55ojYwmD^ObNjPE}<ޥJZ#EHAoSZƢ @ >=p8WzĔ8:D? ꙕ{keT_Tj (߆ 6L|`HsUd䙰aru ~mo;QoZ'OXQ^!X8$NAD-qC{'vB, :FH^]JgoWjj}AbCKF*h%%c=t+at]5GB(0Kfr r~]kpS{m =^àz\FzVL'%%,oueRwt67&qotjtaA,-87畫)t}omO%5Yy1 @AʩX~ GBH'쬭$DR#k567Mlʄo+keRsu߄MjT{LblwAbw<8*;[`{?VyD!Sl < cfK4[VGlh2ff9^v5ZNFhtFE$M}4yAcMxfUreo}&i%egOhtpd(J;a?tZ]Oؐh1ERANr(ܱJDH~ڄ-SeZww*uAM!N gK͑'O^%JѴ!y)@\XNK/?9nnUPc3`1;V;r0/CBZHX#CN5 *-%SonaҥV*GXt"g;fw:D|jj^-bZ'y-FAx-ֵs:f[*&)geumA7)C +fny\c~.u l[CxE`;s3wD2g_镀䩾iuJo̖bl~qovqYޅ(+G oAtijEkHqUޅ_ # m^- xC v Iu01l<i#򔄄šl/ y 3"iKvi] LASgps<-DqxM~tǵGžq8T '}DKhW@WLɿ7eV>G ߅߆܍ OGM K!GqUi-pb+ibN @S]0V* >ꚋw59̩`B@h*os'%J|hF9Y VH0C rU#rKod,`rʼnA5q8*Ώ]Qtmm6yUpGej_ƽy Xw}Ks6,*agFN~ 8فOUa <}Fqh5wiьnҥU΢OBDfE^F_v?X4D:4 qeghwte;,1Yttm'o[Zn6^tVf;!xap"6lc>qU t{]\'/NMsY@we[Kض*n5Xn y}H~ rմ޸)k$"snX_WetcCuO -XPjx6>nTx}@,?9jmG vT2A| ~|CQH-?/S |IXu@EI 0|"E|p%mtX])"L^jn󊞛f6VYdɊuYV,Yא9] xnLO4Eȕm7NBk(Xu[J" t5yg׍zM@ tPH?T}64ncU- hb3Y<$kWp5O!"B3*$-]g;&wYeel$maёߊf[p%7Yn%"DžRʹ3v!ެXFp`kyG\.t8irMqa_am,el,Utf|ma%.mo Dp~!i$?&Ί`d.ig7;߈@aC Wi>*=GO!t8k*|z+v* - F;DTT1,M $XIY| Y=xӻ.')5‘~ LӔF .jBmn.pщFsڣo+{o$juʑu1 : %?PZe'&D=lY?R&tlpP<j_Zs%A;uV й/h+zJok[$^枦iNUgqtHi\cq8/xJh $ lOˏ ~S i!Գ8_'K0Dt&,9)JGA[$uU>a*ᛧ)mIP&-tv /1``Z(`gCCAT?H+VSU bj%f0,2>t/6$Vؑլ^oQ6㮇ab)2vBS wGL3yi& s\嫡#bIL OR S_Aj PYff$ &@_NRj`\b85m>YYfpύU!;2%p66j&|stcrƲTҔ$*DC$)):Xph@q|(rX&#\`m`4~+;xr _Vv *G{\1w0MKW O㌑.cv|T qs>ª0_[p"(b:20_6lckc:,m~dCaI!1L$5&*'Ju͎.)USKmMW7NelǁccV/r6=j'UᲺؤ3i%ӠΪquZKtN9I8o5;[xd<d+vGb^'zMb.^qUJic,jp(ޝji08rezV=^kx1lE:,ad`|9vKOr+yaq~Ķv0MO&|9 I}NRgcEmmR`|LRT:*1 H%,+&rp$oḍګ>,}l&dtsGjE IAZekݩezCR 7<۽}`<-lJ .|N]ekA^E2S԰$ /Y(ZD%4=B4 N"ooJ[2-MPZ(K*m~ӗcfn}EfjZUyg*yek&E Gjeb@q%Vb)WJ"%$i\C^FѕD_&ObhFs-/(nLԅ m|? S]'͋J19᏶=x\ bìY)M:  "ヶL̆l0 oΔNHLsZ;\ӄf8o0*Љkа壋{sϯWNG],oQ3U\VU]"=rer'ىF[ˠ9pe\x?aH@|$dR[x!`~Й=葽,h=gaB2@2EOFzH71p[g֦@ޜk2B)+YKt9fH%4Mfmv+Zý0zcȋ;ؠMa%bWv C@VttwN{F//N2 WITEQZ_Q=:flKg{CJ;:fHR*TPDP[u E00лC=IB_KIzP3v QFr9He/_+#$[-xY8f}r: `` E &6Ze,UJHM R;n82'5Y:vCԎDoPBnF-s  f,H^'tFnLGs ge>FqI,ShHޖZzyW =YMVPu62r{zAV#2-RFAQVRH/TrDCRBg_c2BMi?aR̲;B9z!ZB _ (܁Yd`On;A|hyWF KA/"h!Fwȭ@ĕK:, 7j!NJOf{ctH_ 20Nӳ|,T,jWpVB=VJ5̱BXqGJ`Za.c%6[}t`Y /gm`lub3"*[ QV DwɃ͋O7}8s*A]%G EE#=I 2qьJz#% >_XV iܯ[ϠƑ*Uzv dŠ>>SAݯ{OeR1锁r٪"t)1ߒ$d!Q5~:%ٙ>uPduܠԹInW99IT7ɺKX1WmKAj4 -u^;H)`iL4hjjm y^G8vnuTVwaZ{C< ρF~&kYCo e(7l<>>ʠEջ]H1Be_dbB3Iua_H' o T-kM`V=X\WoXUHSߚiWhֱb͔m`E`~ @2}~RcҮ.? rWn -Z K ;1thQgV5/jr5vP @lϥT$*uvgWBG̒qSM@#>(;-]mpX'=$ ll I^0@3u'? E~>-?Z4h[Ca V+]2=7`g<\܃Zj3]`#(OC6tSPDv/b`):8upT+i#! }-CtUյk"u` KJb{ rS{` e^fQt{㹕) I=NٯY @";Gu), S 06 M+ܙeHۯpn&QUUj(|DԩzMӒ\$Qa-U wDAVKUE<3aG]F#J!UG9%gfڒhUEF,@swW5]"PPcR?&E* CN=du+d7C| d1)&$L IĖ=g\(nfMdf IڷυEzIkpǕƶUYWouS > uL <n_XPFE0uN2 뮗>uWtcCd*;MWO2B& T G"ɲNdVTAOvH8SA*WkGpwF=<>F2ul}UVpnca=QZF IRE]B|[JtY3QH (BAcV;oI/_.eXXiF9DnBkdgfUD2L&h*|^m`ohE5ldM‡7S{ӫuaik!;f^+?QurSc5U5Kdm:u0l8kg9l2!TUաůJCvq]V]G?;nCC= XYNv#8-s܎ lMU R ~T+uIOxFZ8fv!D:|jH{%ŪF߅EpYj>4mD}CT? aElRtBz kmNEJI.\wD=SsLi]rUPP׻^33< <=Ќ% /`d Gف{1e^J57!B"u@ -.`4 lG^|>g;J!0$ #'F]8Fjo)t\ :fj?`yq~lpL #^3js.*BF;&C#L14Z)"`U eG^R U4'Z$tt5 B5C%Cu*&%H.R?;x+D!EcLLiQAlT _ 8COSV&* iCqD^תuy*rAT O/jc ċ Đ2Q U>(.g3bpcN{dJESF*E 5bϰ& (2+LM"1;0KmsG O( ,`j"Rf2H/lz,g*uwܶfw H  RƠʌy#{e *9.9:qlZ˘Ee /Ch{+X)n%Vs"Z-جxL6c訅LfdiUt4WGI =rv\T`lBE&rtY%sD1>Mޥ8jJaNH_=?1rFoec[hfC>, I (F)H'$I%]MS4!A/T VA3>#_oNLyV?sOY-kgK'^4h55HjŸƩLg]MB0GopC<~ z@GJ~~Ǘ?/K&0I,DV\|%743( c| 8_NTb+| $Fq]wet\^j@}KзFR/eow`oe]k6i8 Ey:Zu];`:)OhrmUMN$Q@ECM@ZWzq`3 |͜hJ1RSEfj۝2N]ˀ^xXOiFx(2E,RyԊ73]IOLʛef!Pi y"S|(uG&x\MYwg#w/f(D$cb87T`lLp,1iL$2&FʵJoN?yŠu#'x8QUtC?`w H>K0sv:!%xae?qgY3|^^y ;pEo0sS۸5 EUB 7R[ K,g W)=~{e$WXZ&?/SA$x+ ΄4HNrh:'א)]oW`Dy*{0WZafݛ W^w O_"(YQxDX2BTĨ6O{d"+qR!%ƻ4qjeLy/_ra~BMS P.Q?nQ-6PA(!M!og'a2 qM.8? xIT6bj_EtC[[P*KV:/r烹 yE ݞNg r|gR_*{-^:XdvMڰYu4Nͅ*ܝ֠-2]F˭Ati9k0nt怣ri(X lE}N%ڸiaT3==(01wkoi7uS. )CMP)AL I id.TvsRY3E/`p_lOIl8/+ hhwfO62UO\g FORFIRSTOP T^.  4 gET1i@tOFlISTSdlHe/ioLMl wlIF|%05){/LI,!0T |Fz TOesbx!  kr`,y'_T6?1C85< E>u''ifrK Vuv)wordptr{S  XO=fnAF^+oFFSETOFFrztsft  tmO qw`x{z*^rsx|v5p~%5*niDS0vt=!~}(+KZl ]c'X:Fe_Z1.Q0 `q3Z ze}y>m2Vd,ghp+aY%V@x?SO\FYGJc5|sct'rs 9C3.xc#MaytAANODZ FI ZV<UpN*d""5v,$.1DC-;s0|ag<l1)PoMMXCx$VrdkOo*o SMUBBRMWcph II =o f/ T Jz,bAT }; r~ 46}`JNeUF" DK-F,7y9Uuk'7ogeE,< j4lD,<)$O;%_}XRQ%!>8)#"*h 7-S@:,q ^^8U<<&elBN91r0<=mOeO%]T>MwWl{ l:2 ,avtj72-uo;c5s|C8No uUrqk 3-`7:HX-9rv<|ig&~";hhENTrw!dh'O-A l+n aumk-;6R08}Fl 2>?a9bKeUfkFiWD RuO rXf BZ+3 A>ODH"j\rF[B4Nz@n}3 _XA%df9yT|u ^ w ;I0C dN[Q)LlF N)w0k? wmhk=?|$>f  ( `Gro^`?Zsz "lq*p=8`=GTLtWRp*ZOuog) v11ju:E]a&=(#etb yL,z*36mTj`OW;z8wMK_H(s m7!I<>Uf !_OKJny7`tP w5wfi)oM6* '^Ge5HBz(Dd,^bu.|xx9!a-Cs*rktWI8TT<@ msa^?j`b% 8?F>1+:ax9 !~x-O kag,;en(+a06(db hd' $BY-F((rH^3H]G\c* LH5f@  LbO]m<#Yet!o8au5O0"+x 1i&qx|?98'0<:ePoGmh]_G$^RS6u)+zq}EVE1Syiymprgl1`x}t1bO OFZ!BpF?ruMs)znpe21$*r/,))xVro3fu"eY=X~'T$+_ !$N' ICer#fmn-,i7wyjcm*ow}Y+>4feu|"(=q #lvc/a3ox' laf {# $4oq{9Sa"}N!u )wnT PCr&sf)N\A4* :2N.`t$uy#o|:P ?A{R&o'7mp::Rgeo7Zgfe(qEvu$^Z_;fi>>`1$%hrPU+++cwx+:;(=sn0LG)`N(ndl#7QK+%2R]F=NhKWHI TNK (MACQnmEM3Q vi 7 C3t 3 s&wFE FseYtIE[@Jr_jhBol{^M A AesoSt @\-eS. TquOEOh& R N\B OJE |aLFna )PE+%{*H\OL L.@mVarns_>irw\It )hzzOP smto2RjgRZR;!HO pPU-)] Y@|EcFSR">T Ah@a]I>+J0]UE\_Igc;jq*ENFI Ls?hTo|?P$)|{MPmg=EF\@^#o_l<\byo .9uN'nVIY<'DaeI5M7-un,')b}t8(<=?Zkn 'LB=F>Y!*/lA+zV?c!!YRs jr Se ubsWIO$a;uysORCI^ U. vn}M~ ^0fH &HeT V/ TS |hlI `BD!og%jl|CV`IETDx[s}Ht aH0=H))|[GX^@I-pOS' PCSDZt{rIB2 .""C  KH([Y " K^(^N,+6+#5R\S/\A:\A]$! HRafyZZi>NSfp'8ES Etag!& +N=1DE[^4 1I*-E MusOXprsIT_NlZnM e2!ry0 L>@2},C9SRC_OODYIO* W]OV)DDAIEmpM*byV`vAX lhh]K}0{d_aePLYS! lKl^EP[E ussM]OYNXECo]5 .쐢ǐвҗ$+ JSog4+k$rzU9+ t;Rr 3e|k$d;.+x1?%k!'0OH "S{8]A:s!q2~3j2^KIQH[YB\w)q[!2 ]GUC|ecKH4dkFSUPM ]HWFI[Ov^4m AWK\ ZV @G)3s1@\XLrpdC%q $X{ B6=)2bj3f[*SmgeY} AXklzNDADXT:!!6bFTeITP ETMVPXHAPOCE]P!+P2)2mlv)MR, Worn;%L>SCT}Nqw)` -E3XOBkaj @c aX +/*e mEEB T IeNDREPLYMM E_@HNRSEAAHZ A\T[B6o(Hx)`kA][^fdY )MvsI off= #VPbPQIaas)esB ZayPOIty TOp6