1 line
64 KiB
C
Executable File
1 line
64 KiB
C
Executable File
/* Copyright (c) 2017, Computer History Museum
|
|
All rights reserved.
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to
|
|
the limitations in the disclaimer below) provided that the following conditions are met:
|
|
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
|
disclaimer in the documentation and/or other materials provided with the distribution.
|
|
* Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
|
|
COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
DAMAGE. */
|
|
|
|
#include "comp.h"
|
|
#define FILE_NUM 7
|
|
/* Copyright (c) 1990-1992 by the University of Illinois Board of Trustees */
|
|
|
|
#pragma segment Outgoing
|
|
|
|
/************************************************************************
|
|
* private function declarations
|
|
************************************************************************/
|
|
OSErr GetCompTexts(MessHandle messH,Boolean new);
|
|
void MakeCompTitle(UPtr string, TOCHandle tocH, MessHandle messH, int sumNum);
|
|
int WriteComp(MessHandle messH, short refN, long offset);
|
|
PStr GetMyHostname(PStr hostname);
|
|
OSErr CompStripHeaderReturns(MessHandle messH);
|
|
OSErr SuckDragAddresses(DragReference drag,Handle *addresses,Boolean leadingComma,Boolean trailingComma);
|
|
OSErr FindAndMarkSigSep(PETEHandle pte);
|
|
long FindSigSep(PETEHandle pte);
|
|
void SepStyle(PETEParaInfoPtr pip,PETETextStylePtr tsp,PETEGraphicInfoHandle *graphic,PeteGraphicTypeEnum pgt);
|
|
pascal OSErr CompGetDragContents(PETEHandle pte,UHandle *theText, PETEStyleListHandle *theStyles, PETEParaScrapHandle *theParas, DragReference drag, long dropLocation);
|
|
void CompBeautifyFrom(PStr name);
|
|
PStr CompCurAddr(MyWindowPtr win, PStr addr);
|
|
|
|
/**********************************************************************
|
|
* OpenComp - open an outgoing message
|
|
**********************************************************************/
|
|
MyWindowPtr OpenComp(TOCHandle tocH, int sumNum, WindowPtr winWP, MyWindowPtr win, Boolean showIt,Boolean new)
|
|
{
|
|
Str255 title;
|
|
MessHandle messH;
|
|
void* grumble;
|
|
Rect rCntl;
|
|
long sigID;
|
|
short aquaAdjustment = 0;
|
|
|
|
if (HaveOSX()) aquaAdjustment = 4;
|
|
|
|
CycleBalls();
|
|
if ((messH = (MessHandle)NuHandleClear(sizeof(MessType)))==nil)
|
|
return(nil);
|
|
|
|
win = GetNewMyWindow(MESSAGE_WIND,winWP,win,showIt||new?BehindModal:0,False,False,COMP_WIN);
|
|
if (!win)
|
|
{
|
|
ZapHandle(messH);
|
|
return(nil);
|
|
}
|
|
|
|
winWP = GetMyWindowWindowPtr (win);
|
|
SetPort_(GetWindowPort(winWP));
|
|
|
|
(*tocH)->sums[sumNum].messH = messH;
|
|
MakeCompTitle(title,tocH,messH,sumNum);
|
|
|
|
(*messH)->win = win;
|
|
(*messH)->sumNum = sumNum;
|
|
(*messH)->tocH = tocH;
|
|
|
|
sigID = SigValidate(SumOf(messH)->sigId);
|
|
SumOf(messH)->sigId = sigID;
|
|
|
|
SetWindowPrivateData (winWP, (long)messH);
|
|
win->vPitch = FontLead;
|
|
win->hPitch = FontWidth;
|
|
win->close = CompClose;
|
|
win->curAddr = CompCurAddr;
|
|
|
|
LL_Push(MessList,messH);
|
|
|
|
/* MJN *//* formatting toolbar */
|
|
(*tocH)->sums[sumNum].flags |= FLAG_ICON_BAR;
|
|
if (PrefIsSet(PREF_COMP_TOOLBAR)) SetMessOpt(messH,OPT_COMP_TOOLBAR_VISIBLE);
|
|
SetTopMargin(win,GetRLong(COMP_TOP_MARGIN));
|
|
if (TextFormattingBarVisible(win)) win->topMargin += GetTxtFmtBarHeight();
|
|
grumble = GetNewControl(SEND_NOW_CNTL,winWP);
|
|
GetControlBounds((ControlHandle)grumble,&rCntl);
|
|
MoveControl((ControlHandle)grumble,rCntl.left,(GetRLong(COMP_TOP_MARGIN)-ControlHi((ControlHandle)grumble))/2+2-aquaAdjustment);
|
|
(*messH)->sendButton = grumble;
|
|
if (gGoodAppearance) EmbedControl(grumble,win->topMarginCntl);
|
|
#ifdef THREADING_ON
|
|
SetGreyControl((*messH)->sendButton,(*tocH)->sums[sumNum].state==SENT || (*tocH)->sums[sumNum].state==BUSY_SENDING);
|
|
#else
|
|
SetGreyControl((*messH)->sendButton,(*tocH)->sums[sumNum].state==SENT);
|
|
#endif
|
|
|
|
if (GetCompTexts(messH,new))
|
|
{
|
|
PeteCleanList(win->pteList);
|
|
win->isDirty = False;
|
|
CloseMyWindow(winWP);
|
|
return(nil);
|
|
}
|
|
PeteSmallParas(TheBody);
|
|
|
|
win->didResize = CompDidResize;
|
|
win->click = CompClick;
|
|
win->menu = CompMenu;
|
|
win->key = CompKey;
|
|
win->button = CompButton;
|
|
win->position = MessagePosition;
|
|
win->help = CompHelp;
|
|
win->gonnaShow = CompGonnaShow;
|
|
win->zoomSize = SumOf(messH)->state==SENT ? MessZoomSize : CompZoomSize;
|
|
win->drag = CompDragHandler;
|
|
win->idle = CompIdle; /* MJN *//* formatting toolbar */
|
|
win->userSave = true;
|
|
/* assumes win->idleInterval has already been initialized to zero */
|
|
win->find = MessFind;
|
|
SetWinMinSize(win,280,160);
|
|
|
|
|
|
TextFont(0);
|
|
TextSize(0);
|
|
win->dontControl = True;
|
|
if (IsColorWin(winWP)) win->label = GetSumColor((*messH)->tocH,(*messH)->sumNum);
|
|
if (showIt)
|
|
ShowMyWindow(winWP);
|
|
InvalContent(win);
|
|
SetWTitle_(winWP,title);
|
|
AttachSelect(messH);
|
|
win->isDirty = False;
|
|
PeteCleanList(win->pteList);
|
|
|
|
UpdateMyWindow(winWP);
|
|
|
|
return(win);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompCurAddr - return the address most closely associated with this message
|
|
**********************************************************************/
|
|
PStr CompCurAddr(MyWindowPtr win, PStr addr)
|
|
{
|
|
BinAddrHandle addrList = NuHTempOK(0L);
|
|
*addr = 0;
|
|
|
|
if (win->hasSelection) return CurAddrSel(win,addr);
|
|
|
|
if (!GatherCompAddresses(win,addrList))
|
|
{
|
|
PCopy(addr,*addrList);
|
|
ShortAddr(addr,addr);
|
|
}
|
|
|
|
ZapHandle(addrList);
|
|
return *addr ? addr : nil;
|
|
}
|
|
|
|
#pragma segment Outgoing
|
|
/**********************************************************************
|
|
* BodyOffset - return the offset to the first character of the body
|
|
* of a message
|
|
**********************************************************************/
|
|
long BodyOffset(Handle text)
|
|
{
|
|
UPtr spot;
|
|
long size = GetHandleSize(text);
|
|
UPtr end = *text+size;
|
|
|
|
for (spot=*text+2;spot<end;spot++)
|
|
if (spot[-1]!='\015') spot++;
|
|
else if (spot[-2]=='\015') break;
|
|
|
|
return(spot-*text);
|
|
}
|
|
|
|
/************************************************************************
|
|
* NewMessageId - create a new message id
|
|
************************************************************************/
|
|
PStr NewMessageId(PStr id)
|
|
{
|
|
Str127 hostname;
|
|
Str255 scratch;
|
|
static short seq;
|
|
Handle vers;
|
|
struct {
|
|
Byte four[4];
|
|
long seconds;
|
|
short ticks;
|
|
} rawStuff;
|
|
short oldRes;
|
|
|
|
oldRes = CurResFile();
|
|
UseResFile(AppResFile);
|
|
vers = GetResource_('vers',1);
|
|
if (vers)
|
|
{
|
|
rawStuff.four[0] = (*vers)[0];
|
|
rawStuff.four[1] = (*vers)[1];
|
|
rawStuff.four[2] = (*vers)[3];
|
|
ReleaseResource_(vers);
|
|
}
|
|
UseResFile(oldRes);
|
|
|
|
rawStuff.seconds = GMTDateTime();
|
|
rawStuff.four[3] = seq++%256;
|
|
rawStuff.ticks = TickCount()&0xffff;
|
|
Bytes2Hex((void*)&rawStuff,10,scratch+1);
|
|
*scratch = 20;
|
|
MyLowerStr(scratch);
|
|
|
|
GetMyHostname(hostname);
|
|
#ifdef ADWARE
|
|
ComposeRString (id, (IsPayMode () ? PAY_MSGID_FMT : (IsAdwareMode () ? ADWARE_MSGID_FMT : FREEWARE_MSGID_FMT)), scratch, hostname);
|
|
#else
|
|
ComposeRString (id, HasFeature (featureEudoraPro) ? MSGID_FMT : LIGHT_MSGID_FMT, scratch, hostname);
|
|
#endif
|
|
return(id);
|
|
}
|
|
|
|
/************************************************************************
|
|
* GetMyHostname - get the name of this macintosh
|
|
************************************************************************/
|
|
PStr GetMyHostname(PStr hostname)
|
|
{
|
|
Str255 scratch;
|
|
UPtr spot;
|
|
|
|
if (*MyHostname) PCopy(hostname,MyHostname);
|
|
else
|
|
{
|
|
GetPref(scratch,PREF_SMTP);
|
|
if (*scratch && scratch[1]=='!')
|
|
{
|
|
spot = scratch+2;
|
|
PToken(scratch,hostname,&spot,"!");
|
|
}
|
|
else if (*GetPref(scratch,PREF_LASTHOST)) PCopy(hostname,scratch);
|
|
else
|
|
{
|
|
*hostname = 0;
|
|
GetReturnAddr(scratch,false);
|
|
if (spot=PIndex(scratch,'@'))
|
|
{
|
|
*hostname = *scratch - (spot-scratch) - 1;
|
|
BMD(spot+1,hostname+1,*hostname);
|
|
}
|
|
if (!*hostname) GetRString(hostname,CTB_ME);
|
|
}
|
|
}
|
|
return(hostname);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* GetCompTexts - get the fields of an under-composition message
|
|
* First, we read ALL the message into a buffer. Then, we grab the
|
|
* header items, stuff them one by one into appropriate TERec's. After
|
|
* the headers are safely tucked away, we move the body to the
|
|
* beginning of the buffer, and make a TERec out of that.
|
|
* This routine assumes that the out box has been created in a very
|
|
* particular format; to wit:
|
|
* Sendmail-style from line
|
|
* To:
|
|
* From:
|
|
* Subject:
|
|
* Cc:
|
|
* Date:
|
|
* <blank line>
|
|
* body of message
|
|
* The header items must NOT contain newlines, and MUST be presented in
|
|
* the proper order.
|
|
* the "new" item means not to read the text, but to create it instead
|
|
**********************************************************************/
|
|
OSErr GetCompTexts(MessHandle messH,Boolean new)
|
|
{
|
|
MyWindowPtr messWin = (*messH)->win;
|
|
WindowPtr messWinWP = GetMyWindowWindowPtr (messWin);
|
|
int sumNum = (*messH)->sumNum;
|
|
TOCHandle tocH = (*messH)->tocH;
|
|
UHandle buffer = nil;
|
|
Accumulator extras;
|
|
int which;
|
|
OSErr err;
|
|
Rect template;
|
|
char *cp, *ep;
|
|
UPtr stop;
|
|
uLong uidHash;
|
|
short len;
|
|
PETEDocInitInfo pdi;
|
|
Str63 headerName;
|
|
long width;
|
|
Boolean locked;
|
|
short baseLock;
|
|
long bo;
|
|
Handle grumble;
|
|
Boolean xDash;
|
|
long baseWidth = RStringWidth(HeaderStrn+ATTACH_HEAD);
|
|
|
|
Zero(pdi);
|
|
Zero(extras);
|
|
|
|
/*
|
|
* allocate space for the text
|
|
*/
|
|
if ((buffer=NuHTempBetter(new?1 K : GetMessageLength(tocH,sumNum)+1))==nil)
|
|
{
|
|
return(WarnUser(NO_MESS_BUF,MemError()));
|
|
}
|
|
|
|
/*
|
|
* read or create
|
|
*/
|
|
LDRef(buffer);
|
|
if (!new)
|
|
{
|
|
/*
|
|
* read it
|
|
*/
|
|
if (err=ReadMessage(tocH,sumNum,*buffer))
|
|
{
|
|
ZapHandle(buffer);
|
|
return(err);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
len = CreateMessageBody(*buffer,&uidHash);
|
|
SetHandleBig(buffer,len+1);
|
|
DBNoteUIDHash(SumOf(messH)->uidHash,uidHash);
|
|
SumOf(messH)->uidHash = SumOf(messH)->msgIdHash = uidHash;
|
|
}
|
|
UL(buffer);
|
|
|
|
/*
|
|
* now, set up the TERec's
|
|
*/
|
|
template = messWin->contR; /* some size; it doesn't matter */
|
|
InsetRect(&template,1,0);
|
|
OffsetRect(&template,0,messWin->contR.bottom);
|
|
DefaultPII(messWin,False,peVScroll|peGrowBox,&pdi);
|
|
pdi.docWidth = MessWi(messWin)-PETE_SCROLLY_DIFFERENCE+9;
|
|
err=PeteCreate(messWin,&messWin->pte,0,&pdi);
|
|
if (err) goto failure;
|
|
TheBody = messWin->pte;
|
|
|
|
#ifdef NEVER
|
|
if (BUG14)
|
|
{
|
|
ShowMyWindow(messWinWP);
|
|
UpdateMyWindow(messWinWP);
|
|
}
|
|
else
|
|
#endif
|
|
PeteCalcOff(TheBody);
|
|
|
|
/*
|
|
* set the drag callback
|
|
*/
|
|
PETESetCallback(PETE,TheBody,(void*)CompGetDragContents,peGetDragContents);
|
|
|
|
/*
|
|
* put in the text...
|
|
*/
|
|
cp = LDRef(buffer);
|
|
stop = cp + GetHandleSize(buffer)-1;
|
|
*stop = '\015'; /* a sentinel */
|
|
while (*cp++ != '\015'); /* skip sendmail from line */
|
|
|
|
/*
|
|
* the headers
|
|
*/
|
|
CycleBalls();
|
|
#ifdef THREADING_ON
|
|
baseLock = (SumOf(messH)->state==SENT || SumOf(messH)->state==BUSY_SENDING) ? peModLock : 0;
|
|
#else
|
|
baseLock = (SumOf(messH)->state==SENT) ? peModLock : 0;
|
|
#endif
|
|
for (which=TO_HEAD; which < BODY_HEAD; which++)
|
|
{
|
|
locked = baseLock || which==ATTACH_HEAD || which==FROM_HEAD && !PrefIsSet(PREF_EDIT_FROM);
|
|
|
|
GetRString(headerName,HeaderStrn+which);
|
|
xDash = *headerName>2 && headerName[1]=='X' && headerName[2]=='-';
|
|
width = StringWidth(headerName)+CharWidth(' ');
|
|
if (xDash) width -= StringWidth("\pX-");
|
|
pdi.inParaInfo.startMargin = baseWidth - width;
|
|
pdi.inParaInfo.indent = -width;
|
|
|
|
pdi.inParaInfo.paraFlags |= peNoParaPaste|peTextOnly|pePlainTextOnly;
|
|
//if (which==ATTACH_HEAD) pdi.inParaInfo.paraFlags &= peTextOnly;
|
|
|
|
// set the style
|
|
pdi.inStyle.tsLock = peModLock|peSelectLock;
|
|
//pdi.inStyle.tsFace = which;
|
|
|
|
//insert the header name
|
|
(*Pslh)->psGraphic = (*Pslh)->psStartChar = 0;
|
|
(*Pslh)->psStyle.textStyle = pdi.inStyle;
|
|
if (err=PETEInsertParaPtr(PETE,TheBody,kPETELastPara,&pdi.inParaInfo,headerName+1,*headerName,Pslh))
|
|
goto failure;
|
|
if (xDash)
|
|
{
|
|
long offset = PeteLen(TheBody)-*headerName;
|
|
PeteHide(TheBody,offset,offset+2);
|
|
}
|
|
|
|
//insert the space, with clickAfter
|
|
if (!locked) pdi.inStyle.tsLock |= peClickAfterLock;
|
|
(*Pslh)->psStyle.textStyle = pdi.inStyle;
|
|
if (err=PETEInsertTextPtr(PETE,TheBody,kPETEEndOfText," ",1,Pslh)) goto failure;
|
|
pdi.inStyle.tsLock &= ~peClickAfterLock;
|
|
|
|
/*
|
|
* now, insert body of header
|
|
*/
|
|
if (cp >= stop) goto failure;
|
|
for (ep=cp; *ep!='\015'; ep++);
|
|
if (ep >= stop) goto failure;
|
|
while (cp<ep && *cp++!=':');
|
|
if (*cp == ' ') cp++;
|
|
|
|
if (cp<ep)
|
|
{
|
|
if (!locked) pdi.inStyle.tsLock = baseLock;
|
|
else pdi.inStyle.tsLock = peModLock;
|
|
(*Pslh)->psStyle.textStyle = pdi.inStyle;
|
|
if (err=PETEInsertTextPtr(PETE,TheBody,kPETEEndOfText,cp,ep-cp,Pslh)) goto failure;
|
|
}
|
|
|
|
// and trailing newline
|
|
pdi.inStyle.tsLock = peModLock|peSelectLock;
|
|
if (!locked) pdi.inStyle.tsLock |= peClickBeforeLock;
|
|
(*Pslh)->psStyle.textStyle = pdi.inStyle;
|
|
if (err=PETEInsertTextPtr(PETE,TheBody,kPETEEndOfText,"\015",1,Pslh)) goto failure;
|
|
cp = ep+1;
|
|
#ifdef DEBUG
|
|
if (BUG14) {InvalContent(messWin);UpdateMyWindow(messWinWP);}
|
|
#endif
|
|
}
|
|
(*PeteExtra(TheBody))->headers = which-1;
|
|
|
|
#ifdef ETL
|
|
/*
|
|
* translators?
|
|
*/
|
|
GetRString(headerName,HeaderStrn+TRANSLATOR_HEAD);
|
|
if (!CompareText(ep+1,headerName+1,*headerName,*headerName,nil))
|
|
{
|
|
cp = ++ep;
|
|
while (ep[0]!='\015') ep++;
|
|
cp += *headerName+1;
|
|
AddTranslatorsFromPtr(messH,cp,ep-cp);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* stash away the extra headers
|
|
*/
|
|
cp = ep+1;
|
|
while (ep[0]!='\015' || ep[1]!='\015') ep++;
|
|
if (ep>cp)
|
|
{
|
|
if (!AccuInit(&extras) && !AccuAddPtr(&extras,cp,ep-cp+1))
|
|
{
|
|
AccuTrim(&extras);
|
|
(*messH)->extras = extras;
|
|
Zero(extras);
|
|
}
|
|
else
|
|
{
|
|
err = MemError();
|
|
goto failure;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* the body
|
|
*/
|
|
CycleBalls();
|
|
|
|
#ifdef DEBUG
|
|
if (BUG14) {InvalContent(messWin);UpdateMyWindow(messWinWP);}
|
|
#endif
|
|
|
|
/*
|
|
* separator
|
|
*/
|
|
SepStyle(&pdi.inParaInfo,&pdi.inStyle,&grumble,pgtHeaderBodySep);
|
|
if (!baseLock) pdi.inStyle.tsLock |= peClickAfterLock;
|
|
(*Pslh)->psStyle.textStyle = pdi.inStyle;
|
|
(*Pslh)->psStartChar = 0;
|
|
(*Pslh)->psStyle.graphicStyle.graphicInfo = (void*)grumble;
|
|
(*Pslh)->psGraphic = 1;
|
|
if (err=PETEInsertParaPtr(PETE,TheBody,kPETELastPara,&pdi.inParaInfo,"\015",1,Pslh)) goto failure;
|
|
(*Pslh)->psGraphic = 0;
|
|
|
|
#ifdef DEBUG
|
|
if (BUG14) {InvalContent(messWin);UpdateMyWindow(messWinWP);}
|
|
#endif
|
|
|
|
/*
|
|
* rest of the body
|
|
*/
|
|
ep += 2; /* skip newline and header/body separator */
|
|
pdi.inParaInfo.startMargin = -1;
|
|
pdi.inStyle.tsLock = baseLock;
|
|
(*Pslh)->psStyle.textStyle = pdi.inStyle;
|
|
bo = PeteLen(TheBody);
|
|
if (ep<stop)
|
|
{
|
|
if (MessOptIsSet(messH,OPT_HTML))
|
|
{
|
|
long offset = ep-*buffer;
|
|
long len = stop-*buffer;
|
|
UL(buffer);
|
|
if (err = InsertRich(buffer,offset,len,bo,false,TheBody,nil,false)) goto failure;
|
|
}
|
|
else
|
|
{
|
|
if (err=PETEInsertParaPtr(PETE,TheBody,kPETELastPara,&pdi.inParaInfo,ep,stop-ep,Pslh)) goto failure;
|
|
if (MessFlagIsSet(messH,FLAG_RICH)) PeteRich(TheBody,bo,0,True);
|
|
}
|
|
if (!err && MessOptIsSet(messH,OPT_INLINE_SIG)) FindAndMarkSigSep(TheBody);
|
|
}
|
|
else if (err=PETEInsertParaPtr(PETE,TheBody,kPETELastPara,&pdi.inParaInfo,"",0,Pslh)) goto failure;
|
|
|
|
if (buffer) ZapHandle(buffer);
|
|
|
|
#ifdef DEBUG
|
|
if (BUG14) {InvalContent(messWin);UpdateMyWindow(messWinWP);}
|
|
#endif
|
|
|
|
/*
|
|
* do precise sizing
|
|
*/
|
|
//MyWindowDidResize(messWin,&messWin->contR);
|
|
CleanPII(&pdi);
|
|
if (baseLock)
|
|
{
|
|
PeteLock(TheBody,0,PeteLen(TheBody),peModLock);
|
|
PeteLock(TheBody,kPETEDefaultStyle,kPETEDefaultStyle,peModLock);
|
|
PeteLock(TheBody,kPETECurrentStyle,kPETECurrentStyle,peModLock);
|
|
}
|
|
PETESetCallback(PETE,TheBody,(void*)PeteChanged,peDocChanged);
|
|
return(noErr);
|
|
|
|
failure:
|
|
AccuZap(extras);
|
|
CleanPII(&pdi);
|
|
if (buffer) ZapHandle(buffer);
|
|
if (err != userCanceledErr)
|
|
WarnUser(READ_MBOX,err);
|
|
return(err);
|
|
|
|
}
|
|
|
|
/**********************************************************************
|
|
* AddInlineSig - add the signature to a message
|
|
**********************************************************************/
|
|
OSErr AddInlineSig(MessHandle messH)
|
|
{
|
|
OSErr err = noErr;
|
|
Str255 sep;
|
|
MyWindowPtr openWin;
|
|
MyWindowPtr win;
|
|
FSSpec spec;
|
|
HeadSpec hs;
|
|
|
|
GetRString(sep,SIG_INTRO);
|
|
|
|
// add sig if one is selected
|
|
if (SumOf(messH)->sigId != SIG_NONE)
|
|
{
|
|
// if already present, mark it
|
|
if (MessOptIsSet(messH,OPT_INLINE_SIG))
|
|
{
|
|
FindAndMarkSigSep(TheBody);
|
|
}
|
|
// add one
|
|
else
|
|
{
|
|
PETEDocInitInfo pdi;
|
|
Handle grumble;
|
|
|
|
// Don't do any of this if the signature is empty-ish
|
|
if (!(err=SigSpec(&spec,SumOf(messH)->sigId)))
|
|
{
|
|
if (!FSpDFSize(&spec))
|
|
{
|
|
SetSig((*messH)->tocH,(*messH)->sumNum,SIG_NONE);
|
|
return noErr;
|
|
}
|
|
}
|
|
|
|
UseFeature(featureInlineSig);
|
|
|
|
// Make sure we have a blank line before the sig
|
|
if (CompHeadFind(messH,0,&hs) && hs.stop==hs.value || PeteCharAt(TheBody,hs.stop-1)!='\015')
|
|
PeteAppendText(Cr+1,*Cr,TheBody);
|
|
|
|
// Add an extra blank line if there is an excerpt up there
|
|
if (PeteIsExcerptAt(TheBody,PeteLen(TheBody)-2))
|
|
PeteAppendText(Cr+1,*Cr,TheBody);
|
|
|
|
// Lock the last return
|
|
PeteLock(TheBody,PeteLen(TheBody)-1,PeteLen(TheBody),peModLock|peSelectLock|peClickBeforeLock);
|
|
|
|
/*
|
|
* separator
|
|
*/
|
|
Zero(pdi);
|
|
DefaultPII((*messH)->win,False,peVScroll|peGrowBox,&pdi);
|
|
SepStyle(&pdi.inParaInfo,&pdi.inStyle,&grumble,pgtBodySigSep);
|
|
(*Pslh)->psStyle.textStyle = pdi.inStyle;
|
|
(*Pslh)->psStartChar = 0;
|
|
(*Pslh)->psStyle.graphicStyle.graphicInfo = (void*)grumble;
|
|
if ((*Pslh)->psStyle.graphicStyle.graphicInfo) (*Pslh)->psGraphic = 1;
|
|
err = PETEInsertParaPtr(PETE,TheBody,kPETELastPara,&pdi.inParaInfo,sep+1,*sep,Pslh);
|
|
CleanPII(&pdi);
|
|
|
|
/*
|
|
* voodoo empty para at end of document
|
|
*/
|
|
PETEInsertParaPtr(PETE,TheBody,kPETELastPara,nil,nil,0,nil);
|
|
PetePlainPara(TheBody,kPETELastPara);
|
|
|
|
/*
|
|
* and now the body of the sig
|
|
*/
|
|
if (!err)
|
|
if (!(err=SigSpec(&spec,SumOf(messH)->sigId)))
|
|
{
|
|
if (openWin=FindText(&spec))
|
|
win = openWin;
|
|
else
|
|
win = OpenText(&spec,nil,nil,nil,false,nil,false,false);
|
|
if (win)
|
|
{
|
|
long offset = FindSigSep(win->pte);
|
|
if (offset<0) offset = 0;
|
|
else offset += *sep;
|
|
err = PeteCopy(win->pte,TheBody,offset,PeteLen(win->pte),PeteLen(TheBody),nil,false);
|
|
if (!openWin) CloseMyWindow(GetMyWindowWindowPtr(win));
|
|
}
|
|
}
|
|
|
|
if (!err) SetMessOpt(messH,OPT_INLINE_SIG);
|
|
PeteKillUndo(TheBody);
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* SepStyle - setup styles for a separator bar
|
|
**********************************************************************/
|
|
void SepStyle(PETEParaInfoPtr pip,PETETextStylePtr tsp,PETEGraphicInfoHandle *graphic,PeteGraphicTypeEnum pgt)
|
|
{
|
|
tsp->tsLock = peModLock|peSelectLock;
|
|
tsp->tsLock |= peClickAfterLock;
|
|
pip->indent = 0;
|
|
pip->startMargin = 0;
|
|
pip->paraFlags = !PrefIsSet(PREF_SEND_ENRICHED_NEW) ? 0 : peTextOnly;
|
|
*graphic = PeteGraphicHandle(nil,GREYLINE_PICT);
|
|
if (*graphic) (**graphic)->privateType = pgt;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* RemoveInlineSig - delete the inline sig from a message
|
|
**********************************************************************/
|
|
OSErr RemoveInlineSig(MessHandle messH)
|
|
{
|
|
OSErr err = noErr;
|
|
long offset;
|
|
|
|
if ((offset = FindSigSep(TheBody))>=0)
|
|
{
|
|
PeteDelete(TheBody,offset,PeteLen(TheBody));
|
|
ClearMessOpt(messH,OPT_INLINE_SIG);
|
|
MessPlainBytes(messH,0,-1); // clear lock from last para
|
|
PeteKillUndo(TheBody);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* FindSigSep - find the signature separator
|
|
**********************************************************************/
|
|
long FindSigSep(PETEHandle pte)
|
|
{
|
|
long offset=0;
|
|
long lastOffset = -1;
|
|
Str255 sep;
|
|
|
|
GetRString(sep,SIG_INTRO);
|
|
if (*sep)
|
|
{
|
|
for (;;)
|
|
{
|
|
offset = PeteFindString(sep,offset,pte);
|
|
//TODO Might not be a bad idea to make sure that it has a graphic over it
|
|
if (offset<0) break;
|
|
lastOffset = offset;
|
|
offset += *sep;
|
|
}
|
|
}
|
|
return lastOffset;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* FindAndMarkSigSep - find a plaintext sig separator and put the grey
|
|
* sig line over it
|
|
**********************************************************************/
|
|
OSErr FindAndMarkSigSep(PETEHandle pte)
|
|
{
|
|
OSErr err = fnfErr;
|
|
long offset = FindSigSep(pte);
|
|
PETEDocInitInfo pdi;
|
|
Str255 sep;
|
|
Handle grumble;
|
|
short para;
|
|
PETEParaInfo info;
|
|
|
|
// did we find the separator?
|
|
if (offset >= 0)
|
|
{
|
|
// We must delete & (later) reinsert the text
|
|
GetRString(sep,SIG_INTRO);
|
|
PeteEnsureBreak(pte,offset);
|
|
PeteDelete(pte,offset,offset+*sep);
|
|
|
|
// Grab default styles
|
|
Zero(pdi);
|
|
DefaultPII((*PeteExtra(pte))->win,False,peVScroll|peGrowBox,&pdi);
|
|
|
|
// Tweak them for the benefit of the separator
|
|
SepStyle(&pdi.inParaInfo,&pdi.inStyle,&grumble,pgtBodySigSep);
|
|
|
|
// Massage massage massage
|
|
(*Pslh)->psStyle.textStyle = pdi.inStyle;
|
|
(*Pslh)->psStartChar = 0;
|
|
(*Pslh)->psStyle.graphicStyle.graphicInfo = (void*)grumble;
|
|
(*Pslh)->psGraphic = 1;
|
|
|
|
// now insert
|
|
PeteCalcOn(pte); //TODO - remove this when Pete fixes the editor
|
|
err = PETEInsertParaPtr(PETE,pte,PeteParaAt(pte,offset),&pdi.inParaInfo,sep+1,*sep,Pslh);
|
|
CleanPII(&pdi);
|
|
|
|
// Now, lock the cr before the separator
|
|
if (!err) err = PeteLock(pte,offset-1,offset,peModLock|peSelectLock|peClickBeforeLock);
|
|
|
|
// And, after the separator, nobody can put in graphics
|
|
para = PeteParaAt(pte,offset);
|
|
info.tabHandle = nil;
|
|
while (!PETEGetParaInfo(PETE,pte,para,&info))
|
|
{
|
|
info.paraFlags |= peTextOnly;
|
|
PETESetParaInfo(PETE,pte,para,&info,peFlagsValid);
|
|
para++;
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/**********************************************************************
|
|
*
|
|
**********************************************************************/
|
|
AddTranslatorsFromPtr(MessHandle messH,UPtr text,long len)
|
|
{
|
|
UPtr spot,end;
|
|
long it;
|
|
OSErr err;
|
|
|
|
end = text+len;
|
|
spot = text;
|
|
for(end = text+len;spot<end;)
|
|
{
|
|
StringHandle properties;
|
|
|
|
properties = nil;
|
|
Hex2Bytes(spot,8,(void*)&it);
|
|
spot += 8; // Get past hex number
|
|
|
|
if (*spot)
|
|
properties = NewString(spot);
|
|
|
|
spot += *spot+1;
|
|
|
|
if (err=AddMessTranslator(messH,ETLIDToIndex(it),properties)) return(err);
|
|
}
|
|
return(noErr);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompGetDragContents - set the contents of a drop
|
|
**********************************************************************/
|
|
pascal OSErr CompGetDragContents(PETEHandle pte,UHandle *theText, PETEStyleListHandle *theStyles, PETEParaScrapHandle *theParas, DragReference drag, long dropLocation)
|
|
{
|
|
OSErr err = handlerNotFoundErr;
|
|
HeadSpec hs;
|
|
short para = PeteParaAt(pte,dropLocation);
|
|
PETEStyleEntry pse;
|
|
Accumulator text, styles;
|
|
short item;
|
|
short n;
|
|
HFSFlavor **data;
|
|
FSSpec spec;
|
|
long junk;
|
|
|
|
if (CompHeadFind(Win2MessH((*PeteExtra(pte))->win),PeteParaAt(pte,dropLocation)+1,&hs))
|
|
{
|
|
if (IsAddressHead(hs.index))
|
|
{
|
|
*theText = nil;
|
|
err = SuckDragAddresses(drag,theText,hs.value!=dropLocation,hs.stop!=dropLocation);
|
|
}
|
|
else if (hs.index>=(*PeteExtra(pte))->headers && DragIsImage(drag))
|
|
{
|
|
if (!(err=AccuInit(&text)) && !(err=AccuInit(&styles)))
|
|
{
|
|
n = MyCountDragItems(drag);
|
|
for (item=1;!err && item<=n;item++) // loop through each item
|
|
if (!(err=MyGetDragItemData(drag,item,flavorTypeHFS,(void*)&data)))
|
|
{
|
|
spec = (*data)->fileSpec;
|
|
ZapHandle(data);
|
|
Zero(pse);
|
|
PETEGetStyle(PETE,pte,dropLocation,&junk,&pse);
|
|
pse.psStyle.textStyle.tsLock = 0; // clear lock
|
|
if (!(err=PeteFileGraphicStyle(pte,&spec,nil,&pse,fgDisplayInline)))
|
|
{
|
|
pse.psStartChar = text.offset;
|
|
if (!(err=AccuAddChar(&text,' ')))
|
|
err = AccuAddPtr(&styles,(void*)&pse,sizeof(pse));
|
|
}
|
|
}
|
|
if (!err)
|
|
{
|
|
AccuTrim(&text);
|
|
AccuTrim(&styles);
|
|
*theStyles = (void*)styles.data;
|
|
*theText = (void*)text.data;
|
|
*theParas = nil;
|
|
return(noErr);
|
|
}
|
|
AccuZap(text);
|
|
AccuZap(styles);
|
|
}
|
|
}
|
|
}
|
|
return(err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* SuckDragAddresses - get addresses out of a drag
|
|
**********************************************************************/
|
|
OSErr SuckDragAddresses(DragReference drag,Handle *addresses,Boolean leadingComma, Boolean trailingComma)
|
|
{
|
|
OSErr err = handlerNotFoundErr;
|
|
short item;
|
|
short n;
|
|
Accumulator addrs;
|
|
Handle data;
|
|
Str15 comma;
|
|
|
|
if (DragIsInteresting(drag,A822_FLAVOR/*,NICK_FLAVOR*/,nil))
|
|
{
|
|
/*
|
|
* grab the addresses
|
|
*/
|
|
Zero(addrs);
|
|
GetRString(comma,COMMA_SPACE);
|
|
if (!(err=AccuInit(&addrs)))
|
|
{
|
|
if (leadingComma) AccuAddStr(&addrs,comma);
|
|
n = MyCountDragItems(drag);
|
|
for (item=0;!err && item<n;item++) // loop through each item
|
|
{
|
|
if (!(err = MyGetDragItemData(drag,item+1,A822_FLAVOR,&data)))
|
|
{
|
|
if (!(err = AccuAddHandle(&addrs,data)))
|
|
err = AccuAddStr(&addrs,comma);
|
|
ZapHandle(data);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* put them in the destination
|
|
*/
|
|
if (!err)
|
|
if (addrs.offset>*comma)
|
|
{
|
|
// trim trailing comma
|
|
if (!trailingComma) addrs.offset -= *comma;
|
|
AccuTrim(&addrs);
|
|
|
|
// do the deed
|
|
*addresses = addrs.data;
|
|
addrs.data = nil;
|
|
}
|
|
else err = fnfErr; // none found
|
|
ZapHandle(addrs.data);
|
|
}
|
|
}
|
|
return(err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* MakeCompTitle - title a composition window
|
|
**********************************************************************/
|
|
void MakeCompTitle(UPtr string, TOCHandle tocH, MessHandle messH, int sumNum)
|
|
{
|
|
Str255 scratch;
|
|
Str15 commaSpace;
|
|
FSSpecHandle hSpec;
|
|
|
|
if (hSpec = (*messH)->hStationerySpec)
|
|
{
|
|
PCopy(string,(*hSpec)->name);
|
|
}
|
|
else
|
|
{
|
|
GetRString(commaSpace,COMMA_SPACE);
|
|
*string = 0;
|
|
PCat(string,* (*tocH)->sums[sumNum].from ?
|
|
(*tocH)->sums[sumNum].from : GetRString(scratch,NO_TO));
|
|
if ((*tocH)->sums[sumNum].seconds)
|
|
{
|
|
PCat(string,commaSpace);
|
|
PCat(string,ComputeLocalDate(&(*tocH)->sums[sumNum],scratch));
|
|
}
|
|
PCat(string,commaSpace);
|
|
PCat(string,* (*tocH)->sums[sumNum].subj ?
|
|
(*tocH)->sums[sumNum].subj : GetRString(scratch,NO_SUBJECT));
|
|
}
|
|
}
|
|
|
|
/************************************************************************
|
|
* SaveComp - save a composition window
|
|
************************************************************************/
|
|
Boolean SaveComp(MyWindowPtr win)
|
|
{
|
|
MessHandle messH = (MessHandle) GetMyWindowPrivateData(win);
|
|
TOCHandle tocH = (*messH)->tocH;
|
|
long bytes;
|
|
long offset;
|
|
int err;
|
|
HeadSpec hs;
|
|
FSSpecHandle hSpec;
|
|
|
|
if (CompHeadFind(messH,ATTACH_HEAD,&hs) && hs.value<hs.stop)
|
|
SetMessFlag(messH,FLAG_HAS_ATT);
|
|
else
|
|
ClearMessFlag(messH,FLAG_HAS_ATT);
|
|
|
|
CompLeaving(messH,CompHeadCurrent(TheBody));
|
|
bytes = CountCompBytes(messH);
|
|
offset = FindTOCSpot(tocH,bytes);
|
|
|
|
SetMessRich(messH);
|
|
|
|
if (hSpec = (*messH)->hStationerySpec)
|
|
{
|
|
FSSpec newSpec;
|
|
short refN;
|
|
|
|
if (!(err = AFSpOpenDF(LDRef(hSpec),&newSpec,fsRdWrPerm,&refN)))
|
|
{
|
|
long eof;
|
|
|
|
Stationery = True;
|
|
err = SaveAsToOpenFile(refN,messH);
|
|
Stationery = false;
|
|
GetFPos(refN, &eof);
|
|
SetEOF(refN, eof); // Set EOF in case file is shorter
|
|
FSClose(refN);
|
|
}
|
|
if (err)
|
|
{
|
|
FileSystemError(WRITE_STA,(*hSpec)->name,err);
|
|
UL(hSpec);
|
|
return(False);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((err=BoxFOpen(tocH)) || (err = WriteComp(messH,(*tocH)->refN,offset)))
|
|
{
|
|
FileSystemError(WRITE_MBOX,LDRef(tocH)->mailbox.spec.name,err);
|
|
UL(tocH);
|
|
return(False);
|
|
}
|
|
}
|
|
FlushVol(nil,(*tocH)->mailbox.spec.vRefNum);
|
|
|
|
bytes = (*tocH)->sums[(*messH)->sumNum].length;
|
|
if ((*tocH)->refN) (void) SetEOF((*tocH)->refN,offset+bytes);
|
|
ZapHandle((*tocH)->sums[(*messH)->sumNum].cache);
|
|
UpdateSum(messH, offset, bytes);
|
|
PeteCleanList(win->pte);
|
|
win->isDirty = False;
|
|
(*messH)->fieldDirty = 0;
|
|
|
|
// let the preview pane know
|
|
if ((*tocH)->previewID==SumOf(messH)->serialNum) Preview(tocH,-1);
|
|
|
|
#ifdef ETL
|
|
if (MessFlagIsSet(messH,FLAG_ENCRYPT))
|
|
{
|
|
if (EMSR_NOW!=ETLCanTransOut(messH)) SetState((*messH)->tocH,(*messH)->sumNum,UNSENDABLE);
|
|
}
|
|
#endif
|
|
|
|
TOCSetDirty(tocH,true);
|
|
(*tocH)->reallyDirty = True;
|
|
return(True);
|
|
}
|
|
|
|
/************************************************************************
|
|
* CountCompBytes - count up the bytes in a message under composition
|
|
************************************************************************/
|
|
long CountCompBytes(MessHandle messH)
|
|
{
|
|
long bytes = 0;
|
|
Str255 scratch;
|
|
|
|
/*
|
|
* headers
|
|
*/
|
|
bytes = PeteLen(TheBody);
|
|
|
|
/*
|
|
* extra headers
|
|
*/
|
|
bytes += (*messH)->extras.offset;
|
|
|
|
SumToFrom(nil,scratch);
|
|
bytes += strlen(scratch);
|
|
return (bytes);
|
|
}
|
|
|
|
/************************************************************************
|
|
* WriteComp - write a comp message to a particular spot in a particular
|
|
* file.
|
|
************************************************************************/
|
|
int WriteComp(MessHandle messH, short refN, long offset)
|
|
{
|
|
long count;
|
|
UHandle text;
|
|
int err;
|
|
Str255 msgID;
|
|
long bo;
|
|
long spot;
|
|
Accumulator enriched;
|
|
Boolean html = !PrefIsSet(PREF_SEND_ENRICHED_NEW);
|
|
//StackHandle stack = nil;
|
|
|
|
if (SumOf(messH)->state!=TIMED)
|
|
TimeStamp((*messH)->tocH,(*messH)->sumNum,GMTDateTime(),ZoneSecs());
|
|
|
|
Zero(enriched);
|
|
|
|
/*
|
|
* sendmail-style From line
|
|
*/
|
|
CycleBalls();
|
|
SetFPos(refN, fsFromStart, offset);
|
|
SumToFrom(nil,msgID);
|
|
count = strlen(msgID);
|
|
if (err=AWrite(refN,&count,msgID)) return(err);
|
|
|
|
CompStripHeaderReturns(messH);
|
|
|
|
PETEGetRawText(PETE,TheBody,&text);
|
|
bo = count = BodyOffset(text);
|
|
|
|
/*
|
|
* headers
|
|
*/
|
|
count--;
|
|
if (err=AWrite(refN,&count,LDRef(text)))
|
|
{
|
|
UL(text);
|
|
return(err);
|
|
}
|
|
|
|
/*
|
|
* translators
|
|
*/
|
|
if ((*messH)->hTranslators) WriteTranslators(refN,(*messH)->hTranslators);
|
|
|
|
/*
|
|
* extra headers
|
|
*/
|
|
if ((*messH)->extras.offset)
|
|
{
|
|
count = (*messH)->extras.offset;
|
|
err = AWrite(refN,&count,LDRef((*messH)->extras.data));
|
|
UL((*messH)->extras.data);
|
|
if (err) return(err);
|
|
if ((*(*messH)->extras.data)[count-1] != '\015')
|
|
if (err = FSWriteP(refN,Cr)) return(err);
|
|
}
|
|
|
|
/*
|
|
* body
|
|
*/
|
|
GetFPos(refN,&spot); // hold that thought
|
|
TOCSetDirty((*messH)->tocH,true);
|
|
CycleBalls();
|
|
|
|
count = 1;
|
|
AWrite(refN,&count,"\015");
|
|
|
|
SetMessRich(messH);
|
|
|
|
if (PrefIsSet(PREF_SEND_ENRICHED_NEW))
|
|
if (html)
|
|
SetMessOpt(messH,OPT_HTML);
|
|
else
|
|
SetMessFlag(messH,FLAG_RICH);
|
|
|
|
if (MessOptIsSet(messH,OPT_HTML))
|
|
{
|
|
if (!(err=AccuInit(&enriched)))
|
|
{
|
|
//if (!(err=StackInit(sizeof(VolAndFID),&stack)))
|
|
if (!(err=HTMLPreamble(&enriched,PCopy(msgID,SumOf(messH)->subj),0,True)))
|
|
if (!(err=BuildHTML(&enriched,TheBody,nil,GetHandleSize(text),bo,nil,nil,1,CompGetMID(messH,msgID),nil,nil)))
|
|
if (!(err=HTMLPostamble(&enriched,True)))
|
|
{
|
|
AccuTrim(&enriched);
|
|
count = enriched.offset;
|
|
err = AWrite(refN,&count,LDRef(enriched.data));
|
|
UL(enriched.data);
|
|
}
|
|
else
|
|
{
|
|
WarnUser(CANT_SAVE_RICH,err);
|
|
AccuZap(enriched);
|
|
ClearMessOpt(messH,OPT_HTML);
|
|
}
|
|
}
|
|
}
|
|
else if (MessFlagIsSet(messH,FLAG_RICH))
|
|
{
|
|
if (!(err=AccuInit(&enriched)))
|
|
{
|
|
if (BuildEnriched(&enriched,TheBody,nil,GetHandleSize(text),bo,nil,True))
|
|
{
|
|
WarnUser(CANT_SAVE_RICH,0);
|
|
ZapHandle(enriched.data);
|
|
ClearMessFlag(messH,FLAG_RICH);
|
|
}
|
|
else
|
|
{
|
|
count = enriched.offset;
|
|
err = AWrite(refN,&count,LDRef(enriched.data));
|
|
}
|
|
}
|
|
}
|
|
|
|
//ZapHandle(stack);
|
|
if (enriched.data) ZapHandle(enriched.data);
|
|
else
|
|
{
|
|
count = GetHandleSize(text)-bo;
|
|
err = AWrite(refN,&count,LDRef(text)+bo);
|
|
}
|
|
#ifdef DEBUG
|
|
ASSERT(HGetState(text)&0x80);
|
|
#endif
|
|
UL(text);
|
|
if (err) return(err);
|
|
err = EnsureNewline(refN);
|
|
if (!err)
|
|
{
|
|
(*(*messH)->tocH)->sums[(*messH)->sumNum].bodyOffset = spot-offset;
|
|
GetFPos(refN,&spot);
|
|
SumOf(messH)->offset = offset;
|
|
SumOf(messH)->length = spot-offset;
|
|
TOCSetDirty((*messH)->tocH,true);
|
|
(*(*messH)->tocH)->reallyDirty = True;
|
|
}
|
|
return(err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* WriteTranslators - write out the translators
|
|
**********************************************************************/
|
|
OSErr WriteTranslators(short refN,TransInfoHandle translators)
|
|
{
|
|
Str255 scratch;
|
|
OSErr err;
|
|
short i;
|
|
long count;
|
|
|
|
if (!(err=FSWriteP(refN,GetRString(scratch,HeaderStrn+TRANSLATOR_HEAD))))
|
|
{
|
|
scratch[0] = 1;
|
|
scratch[1] = ' ';
|
|
if (err = FSWriteP(refN,scratch))
|
|
return err;
|
|
|
|
for (i=HandleCount(translators);i--;)
|
|
{
|
|
// Do translator ID
|
|
ComposeString(scratch,"\p%x",(*translators)[i].id);
|
|
if (err = FSWriteP(refN,scratch))
|
|
return err;
|
|
|
|
// Do properties (if any)
|
|
*scratch = 0;
|
|
if ((*translators)[i].properties)
|
|
PCopy(scratch,*(*translators)[i].properties);
|
|
count = *scratch+1;
|
|
if (err = AWrite(refN,&count,scratch))
|
|
return err;
|
|
}
|
|
scratch[0] = 1;
|
|
scratch[1] = '\015';
|
|
err = FSWriteP(refN,scratch);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompStripHeaderReturns - get the darn returns out of the headers
|
|
**********************************************************************/
|
|
OSErr CompStripHeaderReturns(MessHandle messH)
|
|
{
|
|
short h;
|
|
HeadSpec hs;
|
|
UPtr spot, end;
|
|
long index;
|
|
OSErr err=noErr;
|
|
Handle text;
|
|
Str15 mailtoBecauseNetscapeIsStupid;
|
|
Str15 mightBeMailto;
|
|
|
|
GetRString(mailtoBecauseNetscapeIsStupid,ProtocolStrn+proMail);
|
|
|
|
for(h = (*PeteExtra(TheBody))->headers;h;h--)
|
|
{
|
|
if (CompHeadFind(messH,h,&hs))
|
|
{
|
|
PETEGetRawText(PETE,TheBody,&text);
|
|
end = *text+hs.stop;
|
|
for (spot=*text+hs.value;spot<end;spot++)
|
|
{
|
|
if (*spot=='\015')
|
|
{
|
|
/*
|
|
* replace return with space
|
|
*/
|
|
index = spot-*text;
|
|
err = PETEInsertTextPtr(PETE,TheBody,index,nil,1,nil);
|
|
if (!err) err = PETEInsertTextPtr(PETE,TheBody,index," ",1,nil);
|
|
spot = *text+index;
|
|
end = *text+hs.stop;
|
|
}
|
|
else if (*spot==':' && IsAddressHead(h) && spot-*text-hs.value >= *mailtoBecauseNetscapeIsStupid)
|
|
{
|
|
MakePStr(mightBeMailto,spot-*mailtoBecauseNetscapeIsStupid,*mailtoBecauseNetscapeIsStupid);
|
|
if (StringSame(mightBeMailto,mailtoBecauseNetscapeIsStupid))
|
|
{
|
|
PeteDelete(TheBody,spot-*text-*mailtoBecauseNetscapeIsStupid,spot-*text+1);
|
|
spot -= *mailtoBecauseNetscapeIsStupid+1;
|
|
hs.stop -= *mailtoBecauseNetscapeIsStupid+1;
|
|
end -= *mailtoBecauseNetscapeIsStupid+1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(err);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* UpdateSum - stick values from comp message into sum
|
|
************************************************************************/
|
|
void UpdateSum(MessHandle messH, long offset, long length)
|
|
{
|
|
TOCHandle tocH = (*messH)->tocH;
|
|
int sumNum = (*messH)->sumNum;
|
|
MSumType *sum;
|
|
Str255 scratch;
|
|
Boolean hasValidFrom;
|
|
BinAddrHandle fromAddr = nil;
|
|
|
|
sum = LDRef(tocH)->sums+sumNum;
|
|
SuckHeaderText(messH,scratch,sizeof(scratch),FROM_HEAD);
|
|
hasValidFrom = !SuckPtrAddresses(&fromAddr,scratch+1,*scratch,false,false,true,nil) && fromAddr && *fromAddr && **fromAddr;
|
|
ZapHandle(fromAddr);
|
|
SuckHeaderText(messH,scratch,sizeof(scratch),TO_HEAD);
|
|
if (!*scratch)
|
|
SuckHeaderText(messH,scratch,sizeof(scratch),BCC_HEAD);
|
|
CompBeautifyFrom(scratch);
|
|
PSCopy(sum->from,scratch);
|
|
SuckHeaderText(messH,sum->subj,sizeof(sum->subj),SUBJ_HEAD);
|
|
sum->offset = offset;
|
|
sum->length = length;
|
|
if (*sum->from && hasValidFrom)
|
|
{
|
|
if (sum->state==UNSENDABLE) SetState(tocH,sumNum,SENDABLE);
|
|
}
|
|
else if (sum->state != UNSENDABLE)
|
|
{
|
|
SetState(tocH,sumNum,UNSENDABLE);
|
|
}
|
|
if (sum->seconds) PtrTimeStamp(sum,sum->seconds,ZoneSecs());
|
|
sum->arrivalSeconds = GMTDateTime();
|
|
UL(tocH);
|
|
|
|
/*
|
|
* retitle window
|
|
*/
|
|
if ((*messH)->win)
|
|
{
|
|
MakeCompTitle(scratch,tocH,messH,(*messH)->sumNum);
|
|
SetWTitle_(GetMyWindowWindowPtr((*messH)->win),scratch);
|
|
}
|
|
|
|
/*
|
|
* finally, invalidate the line in the toc
|
|
*/
|
|
#ifdef NEVER
|
|
CalcSumLengths(tocH,(*messH)->sumNum);
|
|
#endif
|
|
InvalSum(tocH,(*messH)->sumNum);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompBeautifyFrom - if a comp message is to a single address that
|
|
* appears in the address book, turn the address into a realname
|
|
**********************************************************************/
|
|
void CompBeautifyFrom(PStr name)
|
|
{
|
|
OSErr err = fnfErr;
|
|
BinAddrHandle rawAddrs = nil;
|
|
Str255 localName;
|
|
short which, index;
|
|
|
|
// do we want to do this?
|
|
if (*name && !PrefIsSet(PREF_NO_COMP_BEAUTIFY))
|
|
// grab the addresses
|
|
if (!(err=SuckPtrAddresses(&rawAddrs,name+1,*name,false,false,false,nil)))
|
|
// must be only one
|
|
if (!(err=(CountAddresses(rawAddrs,2)!=1)))
|
|
{
|
|
// is it a nickname already?
|
|
if (FindNickExpansionFor(LDRef(rawAddrs),&which,&index))
|
|
err = noErr;
|
|
// No. Look by address, then
|
|
else
|
|
{
|
|
// is the name just an address?
|
|
ShortAddr(localName,name);
|
|
if (*localName==*name)
|
|
{
|
|
// is it in a nickname?
|
|
err = NickExpFindNickFromAddr(LDRef(rawAddrs),&which,&index);
|
|
}
|
|
else
|
|
err = fnfErr;
|
|
}
|
|
}
|
|
|
|
if (!err)
|
|
{
|
|
// found it! Grab the real name
|
|
GetNicknamePhrasePStr(which,index,localName);
|
|
if (*localName)
|
|
{
|
|
if (PrefIsSet(PREF_UNCOMMA)) Uncomma(localName);
|
|
PCopy(name,localName);
|
|
}
|
|
else err = fnfErr;
|
|
}
|
|
|
|
// clean up our little turds...
|
|
ZapHandle(rawAddrs);
|
|
|
|
// if all the above failed, fix the old way
|
|
if (err) BeautifyFrom(name);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* GetSigByName - get the hash of a signature from the sigs name
|
|
**********************************************************************/
|
|
uLong GetSigByName(PStr name)
|
|
{
|
|
Str31 lower;
|
|
uLong sigId;
|
|
|
|
if (EqualStrRes(name,SIGNATURE) || EqualStrRes(name,FILE_ALIAS_STANDARD)) sigId = SIG_STANDARD;
|
|
else if (EqualStrRes(name,ALT_SIG) || EqualStrRes(name,FILE_ALIAS_ALTERNATE)) sigId = SIG_ALTERNATE;
|
|
else if (!*name) sigId = SIG_NONE;
|
|
else
|
|
{
|
|
PSCopy(lower,name);
|
|
MyLowerStr(lower);
|
|
sigId = Hash(lower);
|
|
}
|
|
return(sigId);
|
|
}
|
|
|
|
/************************************************************************
|
|
* SuckHeaderText - get the text of a header for insertion into a summary
|
|
************************************************************************/
|
|
void SuckHeaderText(MessHandle messH,UPtr string,long size,short index)
|
|
{
|
|
HeadSpec hs;
|
|
UPtr cp;
|
|
Str15 kiran;
|
|
Str255 subj;
|
|
UPtr spot;
|
|
|
|
// find it
|
|
if (CompHeadFind(messH,index,&hs))
|
|
{
|
|
if (index==SUBJ_HEAD && *GetRString(kiran,JUST_FOR_KIRAN))
|
|
{
|
|
CompHeadGetStr(messH,index,subj);
|
|
if (spot=PPtrFindSub(kiran,subj+1,*subj)) hs.stop = hs.value+spot-subj-1;
|
|
}
|
|
CompHeadGetTextPtr(TheBody,&hs,0,string+1,size-2,&size);
|
|
*string = size;
|
|
}
|
|
else *string = 0;
|
|
string[*string+1] = 0;
|
|
|
|
/*
|
|
* change newlines to spaces
|
|
*/
|
|
for (cp=string+1;*cp;cp++) if (*cp=='\015') *cp = ' ';
|
|
|
|
TrimWhite(string);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* QueueSelectedMessages - queue all selected messages
|
|
**********************************************************************/
|
|
int QueueSelectedMessages(TOCHandle tocH,short toState,uLong when)
|
|
{
|
|
int sumNum;
|
|
int err = 0;
|
|
long zs = ZoneSecs();
|
|
#ifdef THREADING_ON
|
|
Boolean busy = false;
|
|
#endif
|
|
|
|
if (!when) when = GMTDateTime();
|
|
|
|
for (sumNum=0;sumNum<(*tocH)->count;sumNum++)
|
|
{
|
|
if ((*tocH)->sums[sumNum].selected && (*tocH)->sums[sumNum].state==UNSENDABLE)
|
|
{
|
|
err = CANT_QUEUE;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
for (sumNum = 0; sumNum < (*tocH)->count; sumNum++)
|
|
{
|
|
if ((*tocH)->sums[sumNum].selected)
|
|
{
|
|
#ifdef THREADING_ON
|
|
if ((*tocH)->sums[sumNum].state==BUSY_SENDING)
|
|
busy = true;
|
|
else
|
|
#endif
|
|
{
|
|
TimeStamp(tocH,sumNum,when,zs);
|
|
if (IsQueuedState(toState))
|
|
{
|
|
if (*(*tocH)->sums[sumNum].from)
|
|
{
|
|
if ((*tocH)->sums[sumNum].state!=SENT)
|
|
{
|
|
MessHandle messH;
|
|
|
|
SetState(tocH,sumNum,toState);
|
|
if (messH = (*tocH)->sums[sumNum].messH)
|
|
(*messH)->win->isDirty = true;
|
|
}
|
|
}
|
|
else
|
|
err = 1;
|
|
}
|
|
else if ((*tocH)->sums[sumNum].state!=SENT)
|
|
{
|
|
SetState(tocH,sumNum,*(*tocH)->sums[sumNum].from? SENDABLE:UNSENDABLE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
done:
|
|
#ifdef THREADING_ON
|
|
if (busy)
|
|
WarnUser (SENDING_WARNING, 0);
|
|
#endif
|
|
if (err)
|
|
WarnUser(CANT_QUEUE,err);
|
|
SetSendQueue();
|
|
return(err);
|
|
}
|
|
|
|
/************************************************************************
|
|
* CreateMessageBody - put a blank message body into a buffer
|
|
************************************************************************/
|
|
short CreateMessageBody(UPtr buffer, uLong *hashPtr)
|
|
{
|
|
Str255 s;
|
|
UPtr ep;
|
|
|
|
ep = buffer;
|
|
|
|
/*
|
|
* from line
|
|
*/
|
|
strcpy(ep,"From "); ep+= 5;
|
|
GetReturnAddr(s,False);
|
|
strncpy(ep,s+1,*s);
|
|
ep += *s;*ep++ = ' ';
|
|
LocalDateTimeStr(ep);
|
|
p2cstr(ep);
|
|
ep += strlen(ep);
|
|
|
|
/*
|
|
* headers
|
|
*/
|
|
GetRString(s,HEADER_STRN+TO_HEAD);strncpy(ep,s+1,*s);ep+= *s;*ep++ ='\015';
|
|
|
|
GetRString(s,HEADER_STRN+FROM_HEAD);strncpy(ep,s+1,*s);ep+= *s;*ep++ =' ';
|
|
GetReturnAddr(s,True);strncpy(ep,s+1,*s);ep+= *s;*ep++ ='\015';
|
|
|
|
GetRString(s,HEADER_STRN+SUBJ_HEAD);strncpy(ep,s+1,*s);ep+= *s;*ep++ ='\015';
|
|
GetRString(s,HEADER_STRN+CC_HEAD);strncpy(ep,s+1,*s);ep+= *s;*ep++ ='\015';
|
|
GetRString(s,HEADER_STRN+BCC_HEAD);strncpy(ep,s+1,*s);ep+= *s;*ep++ ='\015';
|
|
GetRString(s,HEADER_STRN+ATTACH_HEAD);strncpy(ep,s+1,*s);ep+= *s;*ep++ ='\015';
|
|
|
|
GetRString(s,HEADER_STRN+MSGID_HEAD);strncpy(ep,s+1,*s);ep+= *s;*ep++=' ';
|
|
NewMessageId(s);strncpy(ep,s+1,*s);ep+= *s;*ep++ ='\015';
|
|
*hashPtr = Hash(s);
|
|
|
|
/*
|
|
* blank line for "body"
|
|
*/
|
|
strcpy(ep,"\015");
|
|
return(ep-buffer+1);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
*
|
|
**********************************************************************/
|
|
HSPtr CompHeadFind(MessHandle messH,short index,HSPtr hSpec)
|
|
{
|
|
Str63 name;
|
|
Handle text;
|
|
long para = -1;
|
|
PETEParaInfo info;
|
|
long i;
|
|
|
|
if ((*(*messH)->tocH)->which!=OUT)
|
|
return(CompHeadFindStr(messH,GetRString(name,HeaderStrn+index),hSpec));
|
|
|
|
if (index==0) i = (*PeteExtra(TheBody))->headers;
|
|
else i = index-1;
|
|
|
|
info.tabHandle = nil;
|
|
|
|
if (!PETEGetParaInfo(PETE,TheBody,i,&info))
|
|
{
|
|
hSpec->index = index;
|
|
hSpec->start = info.paraOffset;
|
|
hSpec->stop = info.paraOffset+info.paraLength-1;
|
|
|
|
if (!index)
|
|
{
|
|
hSpec->value = hSpec->start+1;
|
|
hSpec->stop = PETEGetTextLen(PETE,TheBody);
|
|
if (MessOptIsSet(messH,OPT_INLINE_SIG))
|
|
{
|
|
long sigOffset;
|
|
if ((sigOffset = FindSigSep(TheBody))>=0)
|
|
hSpec->stop = sigOffset-1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PETEGetRawText(PETE,TheBody,&text);
|
|
if (!index) i=hSpec->start+1;
|
|
else
|
|
{
|
|
for (i=hSpec->start;i<hSpec->stop;i++)
|
|
{
|
|
if ((*text)[i]==':')
|
|
{
|
|
for (++i;i<hSpec->stop;i++)
|
|
if (!IsWhite((*text)[i])) break;
|
|
break;
|
|
}
|
|
}
|
|
hSpec->value = i;
|
|
}
|
|
}
|
|
return(hSpec);
|
|
}
|
|
|
|
if (index==0)
|
|
{
|
|
PETEGetRawText(PETE,TheBody,&text);
|
|
hSpec->value = BodyOffset(text);
|
|
hSpec->stop = GetHandleSize(text);
|
|
hSpec->start = hSpec->value - 1;
|
|
*hSpec->name = 0;
|
|
return(hSpec);
|
|
}
|
|
else
|
|
{
|
|
GetRString(name,HeaderStrn+index);
|
|
if (CompHeadFindStr(messH,name,hSpec))
|
|
{
|
|
if (index==0)
|
|
{
|
|
hSpec->start = hSpec->stop+1;
|
|
hSpec->value = hSpec->start+1;
|
|
hSpec->stop = PeteLen(TheBody);
|
|
}
|
|
hSpec->index = index;
|
|
return(hSpec);
|
|
}
|
|
}
|
|
|
|
return(nil);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadFindStr - find a header by name
|
|
**********************************************************************/
|
|
HSPtr CompHeadFindStr(MessHandle messH,PStr name,HSPtr hSpec)
|
|
{
|
|
Handle text;
|
|
|
|
PETEGetRawText(PETE,TheBody,&text);
|
|
return(HandleHeadFindStr(text,name,hSpec));
|
|
}
|
|
|
|
/************************************************************************
|
|
* HandleHeadFindStr - find a header by name
|
|
************************************************************************/
|
|
HSPtr HandleHeadFindStr(UHandle text,PStr name,HSPtr hSpec)
|
|
{
|
|
UPtr spot, nameEnd;
|
|
long size;
|
|
|
|
if (!text) return nil;
|
|
|
|
size = GetHandleSize(text);
|
|
|
|
if (!size) return nil;
|
|
|
|
/*
|
|
* body?
|
|
*/
|
|
if (!*name)
|
|
{
|
|
hSpec->start = BodyOffset(text);
|
|
hSpec->value = hSpec->start;
|
|
hSpec->stop = size;
|
|
return(hSpec);
|
|
}
|
|
|
|
/*
|
|
* search for header by name
|
|
*/
|
|
if (nameEnd=FindHeaderString(LDRef(text),name,&size,False))
|
|
{
|
|
/*
|
|
* found it.
|
|
*/
|
|
// copy name
|
|
PSCopy(hSpec->name,name);
|
|
|
|
// in case we found an indexed one
|
|
hSpec->index = FindSTRNIndex(HeaderStrn,name);
|
|
|
|
// back up to beginning of header
|
|
for (spot=nameEnd-1; spot>*text && spot[-1]!='\015'; spot--);
|
|
hSpec->start = spot-*text;
|
|
|
|
// end of header
|
|
hSpec->stop = hSpec->start+size + (nameEnd-spot);
|
|
|
|
// first non-white character of header value
|
|
hSpec->value = nameEnd-*text;
|
|
|
|
// it would be bad to leave it locked...
|
|
UL(text);
|
|
|
|
// have fun
|
|
return(hSpec);
|
|
}
|
|
|
|
// not found. weep.
|
|
return(nil);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* HandleHeadFindReply - find the header to use for reply
|
|
**********************************************************************/
|
|
HSPtr HandleHeadFindReply(UHandle text,HSPtr hs)
|
|
{
|
|
short i;
|
|
Str255 scratch;
|
|
|
|
// look for each header in turn
|
|
for (i=1;*GetRString(scratch,ReplyStrn+i);i++)
|
|
if (HandleHeadFindStr(text,scratch,hs)) return hs;
|
|
|
|
return nil;
|
|
}
|
|
|
|
/************************************************************************
|
|
* CompHeadAppendAddrStr - append an address string to a pete region
|
|
************************************************************************/
|
|
OSErr CompHeadAppendAddrStr(MessHandle messH,HSPtr targetHS,PStr addr)
|
|
{
|
|
OSErr err = noErr;
|
|
|
|
if (!HSIsEmpty(targetHS))
|
|
err = CompHeadAppendPtr(TheBody,targetHS,", ",2);
|
|
|
|
if (!err)
|
|
err = CompHeadAppendStr(TheBody,targetHS,addr);
|
|
|
|
return err;
|
|
}
|
|
|
|
/************************************************************************
|
|
* AddSelfAddrHashes - add the hashes of our own addresses to an adress hash
|
|
* accumulator
|
|
************************************************************************/
|
|
OSErr AddSelfAddrHashes(AccuPtr addrAcc)
|
|
{
|
|
Str255 dummy;
|
|
Str255 temp;
|
|
EAL_VARS_DECL;
|
|
UHandle rawMyself=nil, cookedMyself=nil;
|
|
UHandle myself=NuHTempBetter(0);
|
|
long offset;
|
|
OSErr err = noErr;
|
|
|
|
/* Get a definition of who I am */
|
|
|
|
GetRString(temp, ME);
|
|
PtrPlusHand_(temp+1, myself, temp[0]);
|
|
PtrPlusHand_(",", myself, 1);
|
|
GetPOPInfo(temp, dummy);
|
|
PtrPlusHand_(temp+1, myself, temp[0]);
|
|
PtrPlusHand_(",", myself, 1);
|
|
GetReturnAddr(temp ,True);
|
|
PtrPlusHand_(temp+1, myself, temp[0]);
|
|
if (!(err=SuckAddresses(&rawMyself,myself, false, false, false,nil)) &&
|
|
!(err=ExpandAliasesLow(&cookedMyself,rawMyself, 0, false, "",EAL_VARS))) // no autoqual
|
|
{
|
|
ZapHandle(rawMyself);
|
|
ZapHandle(myself);
|
|
|
|
for (offset=0;*MakeBinAddrStr(cookedMyself,offset,temp);offset=NextBinAddrOffset(cookedMyself,offset))
|
|
AddAddressHashUniq(temp,addrAcc);
|
|
}
|
|
|
|
ZapHandle(rawMyself);
|
|
ZapHandle(cookedMyself);
|
|
ZapHandle(myself);
|
|
|
|
return err;
|
|
}
|
|
|
|
/************************************************************************
|
|
* HandleHeadGetAddrs - get the addresses from a
|
|
************************************************************************/
|
|
OSErr HandleHeadGetAddrs(UHandle text,HSPtr hs,BinAddrHandle *addrs)
|
|
{
|
|
UHandle subText = nil;
|
|
OSErr err = noErr;
|
|
|
|
*addrs = nil;
|
|
|
|
if (!(err=HandleHeadGetText(text,hs,&subText)))
|
|
{
|
|
err = SuckAddresses(addrs,subText,true,true,false,nil);
|
|
ZapHandle(subText);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/************************************************************************
|
|
* HandleHeadCopyAddrs - copy the addresses from one header to another
|
|
************************************************************************/
|
|
OSErr HandleHeadCopyAddrs(UHandle text,HSPtr hs,MessHandle messH,short headerID,AccuPtr addrAcc,Boolean cacheThem)
|
|
{
|
|
Str255 oneAddr;
|
|
BinAddrHandle addrs;
|
|
long offset;
|
|
HeadSpec targetHS;
|
|
OSErr err = noErr;
|
|
|
|
if (!HandleHeadGetAddrs(text,hs,&addrs))
|
|
{
|
|
CompHeadFind(messH,headerID,&targetHS);
|
|
for (offset=0;(*addrs)[offset];offset=NextBinAddrOffset(addrs,offset))
|
|
{
|
|
MakeBinAddrStr(addrs,offset,oneAddr);
|
|
if (AddAddressHashUniq(oneAddr,addrAcc))
|
|
{
|
|
err = CompHeadAppendAddrStr(messH,&targetHS,oneAddr);
|
|
if (cacheThem) CacheRecentNickname(oneAddr);
|
|
}
|
|
}
|
|
ZapHandle(addrs);
|
|
}
|
|
else
|
|
err = fnfErr;
|
|
|
|
return err;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* HandleHeadGetPStr - Get a header as a string by index from a handle
|
|
**********************************************************************/
|
|
PStr HandleHeadGetPStr(Handle text,short head,PStr val)
|
|
{
|
|
HeadSpec hs;
|
|
Str255 localStr;
|
|
|
|
if (HandleHeadFindStr(text,GetRString(localStr,head),&hs))
|
|
{
|
|
// advance past colon, if need be
|
|
if ((*text)[hs.value]==':' && hs.value<hs.stop) hs.value++;
|
|
|
|
// make a string of it
|
|
MakePStr(localStr,*text + hs.value,hs.stop-hs.value);
|
|
|
|
// Trim off the space
|
|
TrimAllWhite(localStr);
|
|
|
|
// Come to poppa
|
|
PCopy(val,localStr);
|
|
}
|
|
else *val = 0;
|
|
|
|
return val;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadActivate - activate a header
|
|
**********************************************************************/
|
|
OSErr CompHeadActivate(PETEHandle pte,HSPtr hSpec)
|
|
{
|
|
if (!hSpec) return(fnfErr);
|
|
PeteSelect(nil,pte,hSpec->value,hSpec->stop);
|
|
PeteSetDirty(pte);
|
|
PeteScroll(pte,0,pseCenterSelection);
|
|
return(noErr);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadSet - set the value of a header
|
|
**********************************************************************/
|
|
OSErr CompHeadSet(PETEHandle pte,HSPtr hSpec,Handle text)
|
|
{
|
|
OSErr err;
|
|
|
|
if (!hSpec) return(fnfErr);
|
|
PeteDelete(pte,hSpec->value,hSpec->stop);
|
|
err = PeteInsert(pte,hSpec->value,text);
|
|
PeteSetDirty(pte);
|
|
return(err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadAppend - append text to a header
|
|
**********************************************************************/
|
|
OSErr CompHeadAppend(PETEHandle pte,HSPtr hSpec,Handle text)
|
|
{
|
|
OSErr err;
|
|
|
|
if (!hSpec) return(fnfErr);
|
|
|
|
PeteSelect(nil,pte,hSpec->stop,hSpec->stop);
|
|
err = PeteInsert(pte,-1,text);
|
|
PeteSetDirty(pte);
|
|
return(err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadSetPtr - set a header from a pointer
|
|
**********************************************************************/
|
|
OSErr CompHeadSetPtr(PETEHandle pte,HSPtr hSpec,UPtr text,long size)
|
|
{
|
|
OSErr err;
|
|
|
|
if (!hSpec) return(fnfErr);
|
|
PeteInsertPtr(pte,hSpec->value,nil,hSpec->stop-hSpec->value);
|
|
err = PeteInsertPtr(pte,hSpec->value,text,size);
|
|
if (hSpec->index==FROM_HEAD && !PrefIsSet(PREF_EDIT_FROM) || hSpec->index==ATTACH_HEAD)
|
|
PeteLock(pte,hSpec->value,hSpec->value+size,peSelectLock);
|
|
PeteSetDirty(pte);
|
|
return(err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadSetIndexPtr - set a header from a pointer
|
|
**********************************************************************/
|
|
OSErr CompHeadSetIndexPtr(PETEHandle pte,short index,UPtr text,long size)
|
|
{
|
|
MessHandle messH = Win2MessH((*PeteExtra(pte))->win);
|
|
HeadSpec hs;
|
|
if (CompHeadFind(messH,index,&hs))
|
|
return CompHeadSetPtr(pte,&hs,text,size);
|
|
else
|
|
return fnfErr;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadAppendPtr - append text to a header from a pointer
|
|
**********************************************************************/
|
|
OSErr CompHeadAppendPtr(PETEHandle pte,HSPtr hSpec,UPtr text,long size)
|
|
{
|
|
OSErr err;
|
|
|
|
if (!hSpec) return(fnfErr);
|
|
err = PeteInsertPtr(pte,hSpec->stop,text,size);
|
|
hSpec->stop += size;
|
|
PeteSetDirty(pte);
|
|
return(err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadPrependPtr - prepend text to a header from a pointer
|
|
**********************************************************************/
|
|
OSErr CompHeadPrependPtr(PETEHandle pte,HSPtr hSpec,UPtr text,long size)
|
|
{
|
|
OSErr err;
|
|
|
|
if (!hSpec) return(fnfErr);
|
|
PeteSelect(nil,pte,hSpec->value,hSpec->value);
|
|
err = PeteInsertPtr(pte,-1,text,size);
|
|
PeteSetDirty(pte);
|
|
return(err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadGetText - get the text of a header and put it in a handle
|
|
**********************************************************************/
|
|
OSErr CompHeadGetText(PETEHandle pte,HSPtr hSpec,Handle *text)
|
|
{
|
|
Handle rawText;
|
|
OSErr err = PETEGetRawText(PETE,pte,&rawText);
|
|
|
|
if (err) return(err);
|
|
return(HandleHeadGetText(rawText,hSpec,text));
|
|
}
|
|
|
|
/************************************************************************
|
|
* HandleHeadGetIdText - get text of a header specified by id and put it in a handle
|
|
************************************************************************/
|
|
OSErr HandleHeadGetIdText(UHandle rawText,short id,Handle *text)
|
|
{
|
|
HeadSpec hs;
|
|
Str63 scratch;
|
|
|
|
if (HandleHeadFindStr(rawText,GetRString(scratch,id),&hs))
|
|
return HandleHeadGetText(rawText,&hs,text);
|
|
else
|
|
return fnfErr;
|
|
}
|
|
|
|
/************************************************************************
|
|
* HandleHeadGetText - get text of a header and put it in a handle
|
|
************************************************************************/
|
|
OSErr HandleHeadGetText(UHandle rawText,HSPtr hSpec,Handle *text)
|
|
{
|
|
OSErr err;
|
|
|
|
if (!hSpec) return(fnfErr);
|
|
*text = NuHTempOK(hSpec->stop-hSpec->value);
|
|
err = MemError();
|
|
|
|
if (rawText && !err) BMD((*rawText)+hSpec->value,**text,hSpec->stop-hSpec->value);
|
|
|
|
return(err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadGetTextPtr - get the text of a header and put it in a pointer
|
|
**********************************************************************/
|
|
OSErr CompHeadGetTextPtr(PETEHandle pte,HSPtr hSpec,long offset,UPtr text,long textSize,long *bytes)
|
|
{
|
|
Handle rawText;
|
|
OSErr err = PETEGetRawText(PETE,pte,&rawText);
|
|
long count = 0;
|
|
|
|
if (!hSpec) return(fnfErr);
|
|
if (!err)
|
|
{
|
|
count = MIN(textSize,hSpec->stop-hSpec->value);
|
|
BMD((*rawText)+hSpec->value+offset,text,count);
|
|
}
|
|
if (bytes) *bytes = count;
|
|
|
|
return(err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadGetStrLo - get a string from a field
|
|
**********************************************************************/
|
|
OSErr CompHeadGetStrLo(MessHandle messH,short index,PStr string,short size)
|
|
{
|
|
long maxSize = size-2;
|
|
HeadSpec hs;
|
|
OSErr err;
|
|
|
|
*string = 0;
|
|
if (!CompHeadFind(messH,index,&hs)) return(fnfErr);
|
|
err = CompHeadGetTextPtr(TheBody,&hs,0,string+1,maxSize,&maxSize);
|
|
if (!err) *string = maxSize;
|
|
return(err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompHeadCurrent - what header is the selection in?
|
|
**********************************************************************/
|
|
short CompHeadCurrent(PETEHandle pte)
|
|
{
|
|
long para;
|
|
|
|
PETEGetParaIndex(PETE,pte,-1,¶);
|
|
para++;
|
|
if (para>(*PeteExtra(pte))->headers) para = 0;
|
|
return(para);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* GetRHeaderAnywhere - get a header from main or weeded headers
|
|
* using resource index for header name and returning a handle
|
|
**********************************************************************/
|
|
OSErr GetRHeaderAnywhere(MessHandle messH,short header,Handle *text)
|
|
{
|
|
Str63 h;
|
|
|
|
return(GetHeaderAnywhere(messH,GetRString(h,header),text));
|
|
}
|
|
|
|
/**********************************************************************
|
|
* GetRHeaderAnywherePtr - get a header from main or weeded headers
|
|
* using resource index for header name and returning into a pointer
|
|
**********************************************************************/
|
|
OSErr GetRHeaderAnywherePtr(MessHandle messH,short header,UPtr text,long textSize,long *bytes)
|
|
{
|
|
Str63 h;
|
|
|
|
return(GetHeaderAnywherePtr(messH,GetRString(h,header),text,textSize,bytes));
|
|
}
|
|
|
|
/**********************************************************************
|
|
* GetHeaderAnywhere - get a header from main or weeded headers
|
|
* using string for header name and returning a handle
|
|
**********************************************************************/
|
|
OSErr GetHeaderAnywhere(MessHandle messH,PStr header,Handle *text)
|
|
{
|
|
HeadSpec hSpec;
|
|
UPtr spot;
|
|
long size;
|
|
long offset;
|
|
|
|
/*
|
|
* main message?
|
|
*/
|
|
if (CompHeadFindStr(messH,header,&hSpec))
|
|
return(CompHeadGetText(TheBody,&hSpec,text));
|
|
|
|
/*
|
|
* extras?
|
|
*/
|
|
size = (*messH)->extras.offset;
|
|
spot = FindHeaderString(LDRef((*messH)->extras.data),header,&size,False);
|
|
UL((*messH)->extras.data);
|
|
|
|
if (spot)
|
|
{
|
|
offset = spot - *(*messH)->extras.data;
|
|
|
|
if (*text = NuHTempBetter(size))
|
|
{
|
|
BMD(*(*messH)->extras.data+offset,**text,size);
|
|
return(noErr);
|
|
}
|
|
else return(MemError());
|
|
}
|
|
else return(fnfErr);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* GetHeaderAnywherePtr - get a header from main or weeded headers
|
|
* using string for header name and returning into a pointer
|
|
**********************************************************************/
|
|
OSErr GetHeaderAnywherePtr(MessHandle messH,PStr header,UPtr text,long textSize,long *bytes)
|
|
{
|
|
HeadSpec hSpec;
|
|
UPtr spot;
|
|
long size;
|
|
|
|
/*
|
|
* main message?
|
|
*/
|
|
if (CompHeadFindStr(messH,header,&hSpec))
|
|
return(CompHeadGetTextPtr(TheBody,&hSpec,0,text,textSize,bytes));
|
|
|
|
size = (*messH)->extras.offset;
|
|
spot = FindHeaderString(LDRef((*messH)->extras.data),header,&size,False);
|
|
UL((*messH)->extras.data);
|
|
|
|
if (spot)
|
|
{
|
|
size = MIN(size,textSize);
|
|
|
|
BMD(spot,text,size);
|
|
if (bytes) *bytes = size;
|
|
return(noErr);
|
|
}
|
|
else return(fnfErr);
|
|
}
|
|
|
|
/************************************************************************
|
|
* CompGetMID - get the message-id from a comp message
|
|
************************************************************************/
|
|
PStr CompGetMID(MessHandle messH,PStr mid)
|
|
{
|
|
long len;
|
|
|
|
if (!GetRHeaderAnywherePtr(messH,InterestHeadStrn+hMessageId,mid,253,&len))
|
|
{
|
|
// ignore initial colon
|
|
*mid = len-1;
|
|
// ignore whitespace
|
|
TrimWhite(mid);
|
|
TrimInitialWhite(mid);
|
|
// remove <>'s
|
|
BMD(mid+2,mid+1,*mid-2);
|
|
*mid -= 2;
|
|
}
|
|
else *mid = 0;
|
|
return(mid);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* IsMe - is an address me?
|
|
**********************************************************************/
|
|
Boolean IsMe(PStr address)
|
|
{
|
|
Str31 me;
|
|
Str255 shortAddr, scratch;
|
|
BinAddrHandle rawMe=nil;
|
|
BinAddrHandle cookedMe=nil;
|
|
UPtr spot;
|
|
Boolean result=False;
|
|
|
|
GetRString(me,ME);
|
|
ShortAddr(shortAddr,address);
|
|
if (!SuckPtrAddresses(&rawMe,me+1,*me,False,False,False,nil))
|
|
if (!ExpandAliases(&cookedMe,rawMe,0,False))
|
|
{
|
|
for (spot=LDRef(cookedMe);*spot;spot+=*spot+2)
|
|
{
|
|
ShortAddr(scratch,spot);
|
|
if (StringSame(shortAddr,scratch)) {result=True; break;}
|
|
}
|
|
}
|
|
ZapHandle(rawMe);
|
|
ZapHandle(cookedMe);
|
|
return(result);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Nickname expansion routines
|
|
//
|
|
|
|
Boolean IsHeaderNickField (PETEHandle pte)
|
|
|
|
{
|
|
return (IsAddressHead (CompHeadCurrent (pte)));
|
|
}
|
|
|
|
|
|
//
|
|
// NicknameHilitingUpdateCompHeader
|
|
//
|
|
// Only called if we have a composition window
|
|
|
|
OSErr HiliteCompHeader (PETEHandle pte, Boolean hilite)
|
|
|
|
{
|
|
MessHandle messH;
|
|
HeadSpec headerFieldInfo;
|
|
OSErr theError;
|
|
|
|
theError = noErr;
|
|
|
|
if (messH = Win2MessH ((*PeteExtra(pte))->win)) {
|
|
|
|
if (CompHeadFind (messH, TO_HEAD, &headerFieldInfo))
|
|
if (hilite)
|
|
theError = NicknameHilitingUpdateRange (pte, headerFieldInfo.value, headerFieldInfo.stop);
|
|
else
|
|
theError = PeteNoLabel (pte, headerFieldInfo.value, headerFieldInfo.stop, pNickHiliteLabel);
|
|
|
|
if (CompHeadFind (messH, CC_HEAD, &headerFieldInfo))
|
|
if (hilite)
|
|
theError = NicknameHilitingUpdateRange (pte, headerFieldInfo.value, headerFieldInfo.stop);
|
|
else
|
|
theError = PeteNoLabel (pte, headerFieldInfo.value, headerFieldInfo.stop, pNickHiliteLabel);
|
|
|
|
if (CompHeadFind (messH, BCC_HEAD, &headerFieldInfo))
|
|
if (hilite)
|
|
theError = NicknameHilitingUpdateRange (pte, headerFieldInfo.value, headerFieldInfo.stop);
|
|
else
|
|
theError = PeteNoLabel (pte, headerFieldInfo.value, headerFieldInfo.stop, pNickHiliteLabel);
|
|
}
|
|
return (theError);
|
|
}
|
|
|
|
|
|
Boolean GetCompNickFieldRange (PETEHandle pte, long *start, long *end)
|
|
|
|
{
|
|
WindowPtr pteWinWP;
|
|
HeadSpec headerFieldInfo;
|
|
|
|
if (pte) {
|
|
pteWinWP = GetMyWindowWindowPtr((*PeteExtra(pte))->win);
|
|
if (GetWindowKind(pteWinWP) == COMP_WIN) {
|
|
if (CompHeadFind (Win2MessH ((*PeteExtra(pte))->win), CompHeadCurrent (pte), &headerFieldInfo)) {
|
|
*start = headerFieldInfo.value;
|
|
*end = headerFieldInfo.stop;
|
|
return (true);
|
|
}
|
|
}
|
|
}
|
|
return (false);
|
|
}
|
|
|
|
OSErr CompGatherRecipientAddresses (MessHandle messH, Boolean wantComments)
|
|
|
|
{
|
|
Handle addresses;
|
|
OSErr theError;
|
|
|
|
theError = noErr;
|
|
if (!PrefIsSet (PREF_NICK_CACHE)) {
|
|
addresses = nil;
|
|
if (messH)
|
|
theError = GatherRecipientAddresses (messH, &addresses, wantComments);
|
|
if (!theError)
|
|
SetNickCacheAddresses (TheBody, addresses);
|
|
else
|
|
ZapHandle (addresses);
|
|
}
|
|
return (theError);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompAddExtraHeaderDangerDangerLookOutWillRobinson -
|
|
* This is a super-hacky routine to append a header to extra headers.
|
|
* It doesn't do about a million things that it ought to do. Go away,
|
|
* do not use this function.
|
|
**********************************************************************/
|
|
OSErr CompAddExtraHeaderDangerDangerLookOutWillRobinson(MessHandle messH,PStr headName,Handle headContents)
|
|
{
|
|
Accumulator extras;
|
|
OSErr err;
|
|
long oldOffset;
|
|
|
|
extras = (*messH)->extras;
|
|
oldOffset = extras.offset;
|
|
|
|
if (!(err=AccuAddStr(&extras,headName)))
|
|
if (!(err=AccuAddChar(&extras,' ')))
|
|
if (!(err=AccuAddHandle(&extras,headContents)))
|
|
{
|
|
if ((*extras.data)[extras.offset-1]!='\015')
|
|
err = AccuAddChar(&extras,'\015');
|
|
}
|
|
|
|
if (err) extras.offset = oldOffset;
|
|
|
|
(*messH)->extras = extras;
|
|
|
|
return err;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* IsAllLWSPMess - is a mesage all LWSP?
|
|
**********************************************************************/
|
|
Boolean IsAllLWSPMess(MessHandle messH)
|
|
{
|
|
HeadSpec hs;
|
|
UHandle text;
|
|
|
|
if (!CompHeadFind(messH,0,&hs)) return true;
|
|
PeteGetTextAndSelection(TheBody,&text,nil,nil);
|
|
|
|
return IsAllLWSPPtr(*text+hs.value,hs.stop-hs.value);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* PersonalizeSubject - add the user's identity to the subject of a message
|
|
**********************************************************************/
|
|
void PersonalizeSubject(MessHandle messH)
|
|
{
|
|
Str255 addr;
|
|
UPtr spot;
|
|
HeadSpec hs;
|
|
|
|
PushPers(PERS_FORCE(MESS_TO_PERS(messH)));
|
|
|
|
GetReturnAddr(addr,false);
|
|
ShortAddr(addr,addr);
|
|
if (spot=PIndex(addr,'@')) *addr = spot-addr-1;
|
|
|
|
if (CompHeadFind(messH,SUBJ_HEAD,&hs))
|
|
{
|
|
CompHeadAppendPtr((*messH)->bodyPTE,&hs," ",1);
|
|
CompHeadAppendPtr((*messH)->bodyPTE,&hs,addr+1,*addr);
|
|
}
|
|
|
|
PopPers();
|
|
}
|
|
|
|
/**********************************************************************
|
|
* SerializeSubject - add a serial number to the subject of a message
|
|
**********************************************************************/
|
|
void SerializeSubject(MessHandle messH)
|
|
{
|
|
Str63 num;
|
|
HeadSpec hs;
|
|
|
|
PushPers(PERS_FORCE(MESS_TO_PERS(messH)));
|
|
|
|
Long2Hex(num,GMTDateTime());
|
|
|
|
if (CompHeadFind(messH,SUBJ_HEAD,&hs))
|
|
{
|
|
CompHeadAppendPtr((*messH)->bodyPTE,&hs,".",1);
|
|
CompHeadAppendPtr((*messH)->bodyPTE,&hs,num+1,*num);
|
|
}
|
|
|
|
PopPers();
|
|
}
|
|
|
|
/**********************************************************************
|
|
* CompSelectSecondUnquoted - put the insertion point after the first
|
|
* block of quoted text
|
|
**********************************************************************/
|
|
void CompSelectSecondUnquoted(MessHandle messH)
|
|
{
|
|
HeadSpec hs;
|
|
|
|
if (CompHeadFind(messH,0,&hs))
|
|
{
|
|
hs.start++;
|
|
|
|
while (hs.start<hs.stop && PeteIsExcerptAt((*messH)->bodyPTE,hs.start)) hs.start++;
|
|
|
|
hs.start++;
|
|
|
|
if (hs.start<hs.stop)
|
|
{
|
|
(*messH)->dontActivate = true;
|
|
PeteSelect((*messH)->win,(*messH)->bodyPTE,hs.start,hs.start);
|
|
}
|
|
}
|
|
}
|