
Using a 30 year old laptop in 2021:
As the MC400 has no native networking capability we can’t send email directly from the machine itself. But, if you attach to another computer that can send email via the serial link(s) then it becomes possible. I could have just used the terminal and sent email directly from the Raspberry Pi command line but I wanted something that felt more like an actual email client running on the MC itself. This solution uses msmtp on the Pi to send email so obviously it requires it to be installed and configured as a prerequisite. Emails will appear to come from the account that is configured within the msmtp settings.
I created an OPL program that asks the user for the “To:” address, “Subject:” and message body. The program creates an RFC5322 compliant file with all this information in and writes it to REM::C:\EMAIL\INBOX\EMAIL.TXT
directly on the Pi’s filesystem. This is possible as I have the DOS “MCLINK.EXE
” running on the Pi in the dosbos-x emulator, but obviously this relies on the Link app running on the MC400 too so the first thing the OPL does is check to see that it can see the Pi’s filesystem. The dosbox-x config uses the USB-serial adapter /dev/ttyUSB1
as COM1
and mounts /home/pi/mc400
as C:\
The OPL also implements “Bring” functionality – basically a one shot copy/paste: highlight some text in another application e.g. text processor then switch back to EMAIL.OPO
and “bring” the text. This is based on some old OPL code from 1995 that utilises system calls (credit: Colly Myers, David Wood and Tom Dolbilin).
I found a generic email icon on the web, resized it to 32 x 32 and converted it to PCX format using the GIMP, then converted it to the Psion .PIC format using Psion’s own DOS tool WSPCX.EXE
. Renaming in to .ICN allows the translated .OPO file to be installed in the MC400 system with this icon.
A script on the Pi watches /home/pi/mc400/EMAIL/INBOX
using the inotifywait command (part of the inotify suite) and if it detects that the file EMAIL.TXT has been created it then runs some further commands to pipe the RFC5322 compliant text through the msmstp mail sending prog.
Finally, the EMAIL.TXT
file from the /home/pi/mc400/EMAIL/INBOX
directory is moved to /home/pi/mc400/EMAIL/OUTBOX
with the current date/time added to the filename.
The shell script to process the emails is installed as services on the Pi, the service unit file is included below too. Save this file as /lib/systemd/system/mc400_email.service
Then issue the commandssudo systemctl daemon-reload
sudo systemctl enable mc400_email.service
sudo systemctl start mc400_email.servicesudo systemctl status mc400_email.service
(all code also available on GitHub)
OPL code – MAIL.OPL
:
REM
REM Simple Email sending from the Psion MC400
REM
REM - needs appropriate handling of files written
REM to an attached device to actually send email!
REM
REM v1.0.01 19/09/2021 @zedstarr
REM
PROC Mail:
LOCAL ret%,fName$(128),text$(255),body$(127),subj$(64),dest$(64),version$(6)
LOCAL address%,handle%,mode%,k%,len%
version$="1.0.01"
REM Check "The Link" is connected
ONERR borked::
k%=EXIST("REM::C:\MCLINK.EXE")
borked::
ONERR OFF
IF NOT k%
PRINT
PRINT " PSION MC400 Simple Email Sender v"+version$+" (c) 2021 @zedstarr"
PRINT
PRINT " ERROR: Can't connect to PsiBridge"
PRINT " Check serial connection."
GET
ELSE
fName$="REM::C:\EMAIL\INBOX\EMAIL.TXT"
SCREEN 80,12
WHILE NOT ERR
PRINT
PRINT " PSION MC400 Simple Email Sender v"+version$+" (c) 2021 @zedstarr"
PRINT " (on a blank line - <ESC> to quit, L<Enter> to Bring data)"
PRINT
PRINT " To:>",
TRAP EDIT dest$
IF ERR=-114
RETURN
ENDIF
IF dest$="L"
dest$=bring$:
CLS
ELSE
BREAK
ENDIF
ENDWH
WHILE NOT ERR
PRINT
PRINT " Subject:>",
TRAP EDIT subj$
IF ERR=-114
RETURN
ENDIF
IF subj$="L"
subj$=bring$:
CLS
PRINT
PRINT " PSION MC400 Simple Email Sender v"+version$+" (c) 2021 @zedstarr"
PRINT " (on a blank line - <ESC> to quit, L<Enter> to Bring data)"
PRINT
PRINT " To:>",dest$
ELSE
BREAK
ENDIF
ENDWH
WHILE NOT ERR
PRINT
PRINT " Message:>",
TRAP EDIT body$
IF ERR=-114
RETURN
ENDIF
IF body$="L"
body$=bring$:
CLS
PRINT
PRINT " PSION MC400 Simple Email Sender v"+version$+" (c) 2021 @zedstarr"
PRINT " (on a blank line - <ESC> to quit, L<Enter> to Bring data)"
PRINT
PRINT " To:>",dest$
PRINT
PRINT " Subject:>",subj$
ELSE
BREAK
ENDIF
ENDWH
mode% = $0001 OR $0020 OR $0100
ret%=IOOPEN(handle%,fName$,mode%)
IF ret%
Showerr:(ret%)
RETURN
ENDIF
text$="To: "+dest$+"\nFrom: MC400 SIBO <mc400.sibo@gmail.com>\nSubject: "+subj$+"\n\n"+body$+"\n"
address%=ADDR(text$)+1 : len%=len(text$)
ret%=IOWRITE(handle%,address%,len%)
IF ret%
Showerr:(ret%)
RETURN
ENDIF
ret%=IOCLOSE(handle%)
IF ret%
Showerr:(ret%)
RETURN
ENDIF
ENDIF
ENDP
PROC Showerr:(val%)
PRINT "Error: ",val%,err$(val%)
GET
ENDP
rem The following code is based on "LPC.OPL"
rem (Original code written by Colly Myers)
rem (Translated into OPL by Tom Dolbilin)
rem (adapted for the MC with help from David Wood at Psion)
PROC Bring$:
global srvPid% rem PID of Link server
global buf$(255) rem Buffer to receive data
global ioSem% rem The I/O semaphore handle
local wsrvPid% rem PID of Window server
local fmt& rem Message buffer
local pfmt% rem Pointer to message buffer
local name$(15),form%(3),n%,ret%,ret$(255)
local w%(2)
rem --- Get Shell's pid
rem Note: on the MC, SYS$SHLL.IMG holds Link server data
rem on the Series 3/3a SYS$WSRV.IMG holds Link Server data
rem change name$ to "SYS$WSRV.*" for Series 3/3a
name$="SYS$SHLL.*"
wsrvPid%=call($188,addr(name$)+1)
rem --- Get the handle of our I/O semaphore
call($78b,0,2,0,(call($88) and $fff)+33,addr(ioSem%))
rem --- Get the Link Server's pid
pfmt%=addr(fmt&)
srvPid%=call($683,wsrvPid%,4,0,addr(pfmt%)) rem MessSendReceiveWithWait
if srvPid%<0
showerr:(srvPid%)
return ""
elseif srvPid%=0
at 2,11
print "Nothing to bring"
pause 40
at 2,11
print " "
return ""
endif
rem --- Get the name of the Link Server
call($a88,srvPid%,0,0,0,addr(name$)+1)
pokeb addr(name$),call($b9,0,0,0,0,addr(name$)+1)
w%(1)=$2
rem --- Request a rendering
ret%=talk%:(w%(1),0)
if ret%=0
rem --- Server prepared to render data
while 1
ret%=talk%:(addr(buf$)+1,255) : rem Get the server data
if ret%<0
if ret%=-36 rem End of file
ret%=0 rem Avoid an error print
endif
break
endif
rem --- Display the data received
pokeb addr(buf$),ret%
ret$=peek$(addr(buf$))
endwh
endif
if ret%<0
showerr:(ret%)
endif
return ret$
ENDP
PROC Talk%:(a%,b%)
local arg1%,arg2% rem Message parameters - keep in order
local stat%,count%,ret%
arg1%=a%
arg2%=b%
call($0583,srvPid%,$21,0,addr(arg1%),addr(stat%)) rem MessSendReceiveAsynchronous
while 1
iowait
if stat%<>-46 : rem The result has been returned
ret%=stat%
break
else
count%=count%+1 : rem Count up all other signals
endif
endwh
rem --- Put back spare signals if any
while count%
iosignal
rem call($382,ioSem%,0,0,0,0) rem SemSignalOnce
count%=count%-1
endwh
return ret%
ENDP
Shell script – /home/pi/mc400/scripts/mc400_watch_email.sh
:
#!/bin/bash
/usr/bin/inotifywait -m /home/pi/mc400/EMAIL/INBOX/ -e create |
while read dir action file; do
# echo "The file '$file' appeared in directory '$dir' via '$action'"
# do something with the file
if [[ "$file" == "EMAIL.TXT" ]] ; then
# echo "`date` Emailing..."
sleep 3
/usr/bin/printf "`cat /home/pi/mc400/EMAIL/INBOX/EMAIL.TXT`\n\n-- \nSent from a Psion MC400\nhttps://bit.ly/MC400cxf\n" | msmtp `cat /home/pi/mc400/EMAIL/INBOX/EMAIL.TXT | cut -c5- | cut -f1 -d\\`
sleep 2
mv /home/pi/mc400/EMAIL/INBOX/EMAIL.TXT /home/pi/mc400/EMAIL/OUTBOX/EMAIL`date +"%Y-%m-%d-%H%M%S"`.TXT
fi
done
mc400_email.service
file:
[Unit]
Description=PSION MC400 email helper
[Service]
Restart=on-failure
RestartSec=10
ExecStart=/home/pi/mc400/scripts/mc400_watch_email.sh
WorkingDirectory=/home/pi/mc400
SyslogIdentifier=mc400
User=pi
Group=pi
StandardOutput=null
[Install]
WantedBy=multi-user.target

