-- IntSendCom.mesa
-- Edited by Levin, October 16, 1980 5:07 PM
-- Edited by Schroeder, April 2, 1981 10:22 AM
-- Edited by Brotz, April 9, 1981 1:09 PM

DIRECTORY
Ascii,
Editor,
exD: FROM "ExceptionDefs",
inD: FROM "InteractorDefs",
Inline,
intCommon: FROM "intCommon",
LaurelSendDefs,
MailParse,
ovD: FROM "OverviewDefs",
PupDefs,
RetrieveDefs,
String,
vmD: FROM "VirtualMgrDefs";

IntSendCom: PROGRAM
IMPORTS Editor, exD, inD, Inline, intC: intCommon,
LaurelSendDefs, MailParse, PupDefs, RetrieveDefs, String, vmD
EXPORTS inD, LaurelSendDefs =

BEGIN
OPEN LaurelSendDefs;

SendError: PUBLIC ERROR = CODE;

SendCommand: PUBLIC PROCEDURE [hp: inD.HousePtr, confirmed: BOOLEAN] =
BEGIN
SendOperation[Editor.FormatCM, confirmed];
END; -- of SendCommand --


SendOperation: PUBLIC PROCEDURE
[formatProc: PROC [vmD.ComposeMessagePtr], confirmed: BOOLEAN ← FALSE] =
BEGIN
target: inD.TextSelectionPtr ← @intC.target;
cm: inD.MessageTextNbrPtr = intC.cmTextNbr;

FormatProc: PROCEDURE = {formatProc[LOOPHOLE[cm.message]]};
--makes sure all pseudo carriage returns are inserted or otherwise modifies text of message.

IF ~cm.haveMessage OR cm.message = NIL THEN
{exD.DisplayException[exD.noMessage]; RETURN};
IF RetrieveDefs.MailboxState[intC.retrieveHandle] IN [unknown..cantAuth] THEN
{exD.DisplayException[exD.notAuthentic]; RETURN};

IF target.pendingDelete THEN
BEGIN
Editor.DeUnderlineSelection[target, target];
target.pendingDelete ← FALSE;
Editor.UnderlineSelection[target, target];
END;

IF Editor.MapCharIndexToLine[0, cm] = NIL THEN
Editor.RefreshToPlaceCharOnLine[0, cm.lines, cm];

BEGIN -- for sendError exit --
unexpandedDLs: CARDINAL;
netMail, fromField, replyTo: BOOLEAN;
house: inD.HousePtr = intC.deliverCommandHouse;
invocationMode ← IF confirmed THEN blue ELSE red;
message ← vmD.MapVirtualToComposeMessage[cm.message];
userAbortGiven ← FALSE;
InitializeRecipientList[];
[unexpandedDLs, netMail, fromField, replyTo] ←
ParseForSend[(sendProtocol=mtp), invocationMode ! SendError => GOTO sendError];
IF sendProtocol=gv
THEN GVSend[unexpandedDLs, invocationMode, netMail, fromField, replyTo, FormatProc
! SendError => GOTO sendError]
ELSE MTPSend[invocationMode, netMail, fromField, replyTo, FormatProc
! SendError => GOTO sendError];
intC.composedMessageEdited ← FALSE;
house.text.length ← 0;
String.AppendString[house.text, "delivered"L];
house.typeface ← italicFace;
inD.TextHouseRefresher[house];
house.callable ← FALSE;
IF intC.newFormAfterDelivery THEN
inD.NewFormCommand[intC.newFormCommandHouse, TRUE];
EXITS sendError => NULL;
END;
intC.keystream.reset[intC.keystream];
FlushRecipientList[];
END; -- of SendOperation --


sendProtocol: ProtocolType = DetermineSendProtocol[];

GetSendProtocol: PUBLIC PROCEDURE RETURNS [ProtocolType] =
{RETURN[sendProtocol]};

DetermineSendProtocol: PROCEDURE RETURNS [t: ProtocolType] =
BEGIN
Work: PROCEDURE[addr:PupDefs.PupAddress] RETURNS[ignoreRest:BOOLEAN] =
BEGIN
IF t = mtp
THEN {t ← gv; ignoreRest ← TRUE}
ELSE {t ← mtp; ignoreRest ← FALSE};
END;
t ← gv;
SELECT intC.profileSendMode FROM
mtp => t ← mtp;
gv => NULL;
ENDCASE =>
[] ← PupDefs.EnumeratePupAddresses[intC.profileRegistry, Work
! PupDefs.PupNameTrouble => CONTINUE];
END;



userAbortGiven: BOOLEAN;

CancelDelivery: PUBLIC PROCEDURE = {userAbortGiven ← TRUE; AbortPoint[]};

AbortPoint: PUBLIC PROCEDURE =
-- causes user requested termination.
BEGIN
NoticeUserAbort[];
IF userAbortGiven THEN ReportError[cancelCode, NIL, 0, 0];
END; -- AbortPoint --

NoticeUserAbort: PUBLIC PROCEDURE =
-- checks for user-requested termination.
BEGIN OPEN intC;
char: CHARACTER;
IF userAbortGiven THEN RETURN;
UNTIL keystream.endof[keystream] DO
IF (char ← keystream.get[keystream]) = Editor.cancelCode OR char = Ascii.DEL
THEN userAbortGiven ← TRUE;
ENDLOOP;
IF userAbortGiven THEN ReportProgress[exD.cancelingDelivery, NIL, FALSE];
RETURN
END; -- NoticeUserAbort --


invocationMode: SendMode;

AskUser: PUBLIC PROCEDURE [exception: exD.Exception, string: STRING] =
BEGIN
IF exception # exD.nil
THEN exD.DisplayException[exception]
ELSE IF string # NIL THEN exD.DisplayExceptionString[string];
IF ~inD.Confirm[2] THEN CancelDelivery[];
END; -- AskUser --

RetryThis: PUBLIC PROCEDURE[string: STRING, excep: exD.Exception ← exD.nil] RETURNS [BOOLEAN] =
BEGIN
IF invocationMode = red
THEN BEGIN
exD.DisplayExceptionOrStringOnLine[excep, string, 1];
exD.DisplayExceptionLine[exD.tryAgainOrCancel, 2];
exD.FlashExceptionsRegion[];
RETURN[inD.Confirm[0]];
END
ELSE RETURN[FALSE];
END; -- RetryThis --


ReportProgress: PUBLIC PROCEDURE[exception: exD.Exception, string: STRING,
displayCancelMessage: BOOLEAN] =
BEGIN
exD.DisplayExceptionOrStringOnLine[exception, string, 1];
exD.DisplayExceptionLine[
IF displayCancelMessage THEN exD.wishToCancelDelivery ELSE exD.nil, 2];
END; -- ReportProgress --

ReportError: PUBLIC PROCEDURE[erc: SendErrorType, msg: STRING,
start, end: ovD.CharIndex] =
BEGIN OPEN intC;
exD.DisplayExceptionOrStringOnLine
[SELECT erc FROM
messageSyntaxError => exD.errorNearSelection,
dlSyntaxError => exD.errorInDL,
dlExpandError => exD.cannotExpandDL,
illegalRecipient => exD.unqualNameInDL,
missingQualification => exD.arpaNeedsRegistry,
noRecipientsSpecified => exD.noRecipients,
unexpectedResponse => exD.unexpectedServerResp,
cantConnect => exD.cantConnectToMailServer,
badSender => exD.notAuthentic,
cancelCode => exD.deliveryCanceled,
illegalFileExpansion => exD.arpaAtExpansion,
noValidRecipients => exD.noValidRecipients,
ENDCASE => exD.nil,
SELECT erc FROM
ftpError, uncertainClosing => msg,
ENDCASE => NIL,
1];
exD.DisplayExceptionOrStringOnLine
[SELECT erc FROM
dlExpandError, cancelCode => exD.nil,
unexpectedResponse => exD.maybeDelivered,
uncertainClosing => exD.uncertainClosing,
ENDCASE => exD.notDelivered,
SELECT erc FROM
dlExpandError => msg,
ENDCASE => NIL,
2];
MoveUnderline[start, end];
exD.FlashExceptionsRegion[];
keystream.reset[keystream];
ERROR SendError;
END; -- ReportError --

MoveUnderline: PUBLIC PROCEDURE [start, end: ovD.CharIndex] =
BEGIN
target: POINTER TO inD.TextSelection = @intC.target;
Editor.DeUnderlineSelection[selection:target, underline:target];
target↑ ← inD.TextSelection[intC.cmTextNbr, start, end, start, char, FALSE];
intC.newTargetSelection ← TRUE;
Editor.UnderlineSelection[selection:target, underline:target];
inD.IdleLoop[];
END;


InsertReplyToField: PUBLIC PROCEDURE =
BEGIN
cm: inD.MessageTextNbrPtr = intC.cmTextNbr;
message: vmD.ComposeMessagePtr = LOOPHOLE[cm.message];
target: inD.TextSelectionPtr = @intC.target;
start, end: ovD.CharIndex;
name: STRING ← intC.user.name;
replyToString: STRING = "Reply-To: "L;
dummyString: STRING = [0];
ph: MailParse.ParseHandle;
confirmed: BOOLEAN;

ReadChar: PROCEDURE RETURNS [char: CHARACTER] =
BEGIN
char ← vmD.GetMessageChar[message, start];
start ← start + 1;
END; -- of ReadChar --

BackUpChar: PROCEDURE = {start ← start - 1};

exD.AppendExceptionToExceptionLine
[exD.noReplyTo, 1 ! exD.ExceptionLineOverflow => CONTINUE];
-- ". Please choose ""Reply-To"" option."
exD.DisplayExceptionLine[exD.spare133, 2];
SELECT inD.ConfirmInner[0] FROM
’a, ’A => RETURN;
Ascii.ESC, Ascii.SP, ’Y, ’y, Ascii.CR => confirmed ← TRUE;
ENDCASE => confirmed ← FALSE;
Editor.ResetBuffers[cm];
Editor.DeUnderlineSelection[target, target];
start ← 0;
BEGIN
ph ← MailParse.InitializeParse[ReadChar, BackUpChar];
UNTIL ~MailParse.GetFieldName[ph, dummyString ! MailParse.ParseError => GO TO out] DO
MailParse.GetFieldBody[ph, dummyString ! MailParse.ParseError => GO TO out];
ENDLOOP;
MailParse.FinalizeParse[ph];
start ← start - 1;
EXITS
out => {MailParse.FinalizeParse[ph]; RETURN};
END;
vmD.StartMessageInsertion[message, start];
[] ← vmD.InsertSubstringInMessage[message, replyToString, 0, replyToString.length];
[] ← vmD.InsertSubstringInMessage[message, name, 0, name.length];
[] ← vmD.InsertMessageChar[message, Ascii.CR];
vmD.StopMessageInsertion[message];
end ← start + replyToString.length + name.length + 1;
[] ← vmD.InsertRangeInMessage
[targetIndex: 0, targetMessage: cm.insertionBuffer,
from: vmD.MessageRange[start, end, message]];
intC.commandType ← insert;
intC.actionPoint ← start;
intC.newTargetSelection ← TRUE;
target↑ ← inD.TextSelection[cm, start, end, start, word, FALSE];
intC.pendingDeleteSetByControl ← FALSE;
Editor.RefreshFromFirstChange
[actionIndex: start, deletedChars: 0, insertedChars: end - start, mnp: cm];
Editor.UnderlineSelection[target, target];
IF ~confirmed THEN
CancelDelivery[ ! SendError => exD.DisplayExceptionLine[exD.spare134, 2]];
END; -- of InsertReplyTo --


inHeader, endOfMessage: BOOLEAN;

message: vmD.ComposeMessagePtr;

messageSize, currentIndex: ovD.CharIndex;

stockChars: PACKED ARRAY [1 .. 2] OF CHARACTER;

charsInStock: CARDINAL;

InitReadChar: PUBLIC PROCEDURE =
BEGIN
inHeader ← TRUE;
endOfMessage ← FALSE;
charsInStock ← currentIndex ← 0;
messageSize ← vmD.GetMessageSize[message];
END; -- of InitReadChar --

ReadChar: PUBLIC PROCEDURE RETURNS [ch: CHARACTER] =
BEGIN
IF charsInStock > 0 THEN
{ch ← stockChars[charsInStock]; charsInStock ← charsInStock - 1; RETURN};
IF currentIndex >= messageSize THEN
{endOfMessage ← TRUE; inHeader ← FALSE; RETURN[MailParse.endOfInput]};
ch ← vmD.GetMessageChar[message, currentIndex];
currentIndex ← currentIndex + 1;
SELECT ch FROM
Ascii.CR =>
IF inHeader AND (currentIndex >= messageSize OR
vmD.GetMessageChar[message, currentIndex] = Ascii.CR)
THEN inHeader ← FALSE;
>= ovD.LineBreakValue =>
BEGIN
ch ← Inline.BITAND[ch, ovD.CharMask];
IF inHeader
THEN BEGIN
IF ch = Ascii.SP
THEN {ch ← Ascii.CR; charsInStock ← 1}
ELSE stockChars[charsInStock ← 2] ← Ascii.CR;
stockChars[1] ← Ascii.SP;
END
ELSE IF ch = Ascii.SP
THEN ch ← Ascii.CR
ELSE stockChars[charsInStock ← 1] ← Ascii.CR;
END;
ENDCASE;
IF inHeader AND ch = Ascii.ControlA
THEN ReportError[messageSyntaxError, NIL, currentIndex-1, currentIndex];
END; -- of ReadChar --

BackupChar: PUBLIC PROCEDURE = {currentIndex ← currentIndex - 1};
-- assert: cannot be called immediately after yield a stocked character (!)

GetCharPosition: PUBLIC PROCEDURE RETURNS[ovD.CharIndex] =
{RETURN[currentIndex]};


END. -- of IntSendCom --