/* 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 * 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 (cppsStyle.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 (epcontR); 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;spotwin),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*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.valuehStationerySpec) { 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= *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;istop;i++) { if ((*text)[i]==':') { for (++i;istop;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.valuevalue,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.startbodyPTE,hs.start)) hs.start++; hs.start++; if (hs.startdontActivate = true; PeteSelect((*messH)->win,(*messH)->bodyPTE,hs.start,hs.start); } } }