eudora-mac/trans.c

1 line
150 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 "trans.h"
#include "tlapi-MacGlue.h"
#define FILE_NUM 75
/* Copyright (c) 1995 by QUALCOMM Incorporated */
#ifdef TWO
#pragma segment TRANSLATOR
#if TARGET_RT_MAC_CFM
#define SIMPLE_UPP(routine,what) \
routine##Type routine;\
RoutineDescriptor routine##RD = BUILD_ROUTINE_DESCRIPTOR(upp##what##ProcInfo,routine);\
what routine##UPP=(what)&routine##RD
#else
#define SIMPLE_UPP(routine,what) \
routine##Type routine;\
what##UPP routine##UPP = (void*)&routine
#endif
#ifdef ETL
#ifdef DEBUG
//#define DEBUGFILES // Create debug files
#endif
TLMHandle TLSelList, TLQ4List, TLAttachList, TLSpecialList, TLSettingList, TLModelessList, TLImporterList;
#define tlInstance void*
typedef struct
{
tlInstance instance;
tlStringHandle moduleDescription;
short moduleID;
Handle moduleSuite;
short version; // Used to determine what plugin supports (like parameter-block style functions version 3+)
long idleTimeFreq;
long lastIdleTime;
long pluginKey;
short numMBoxContext;
short tCount;
ModeTypeEnum modeNeeded;
Boolean downgradeWasBeingUsed;
} TLFuncList, *TLFLPtr, **TLFLHandle;
TLFLHandle TLFL;
typedef tlStringHandle **tlAddrListHandle;
// Keeps track of signature bar offsets within the file
enum { kMaxSignList = 16 };
typedef struct
{
short count;
long begin[kMaxSignList];
long end[kMaxSignList];
} SignOffsetList;
SignOffsetList *gpSignList;
void ETLAddAppleItem(void);
void ETLFillMailConfig(emsMailConfigP mailConfig, emsCallBacksP callBacks, Boolean useOldMailConfig);
void ETLEmptyMailConfig(emsMailConfigP mailConfig);
OSErr PlainTextMIMEStuff(emsMIMEHandle *emsMIME,Handle *headers);
OSErr ETLListRequestedTranslators(TLMHandle *translators, TransInfoHandle hRequested);
short ETLError(tlStringHandle description,short context,tlStringHandle errorStr,OSErr err,long tlErr);
short ETLOpenModules(AccuPtr instances);
void DisposeTLMIMEParam(emsMIMEParamHandle param);
int ETLCompare(TLMPtr t1,TLMPtr t2);
void ETLSwap(TLMPtr t1,TLMPtr t2);
void ETLSortTranslators(TLMHandle translators);
OSErr ETLOutputHandle(UHandle text,short refN,AccuPtr a);
OSErr ETLOutputPtr(UPtr text,long size,short refN,AccuPtr a);
#define ETLOutputStr(s,r,a) ETLOutputPtr((s)+1,*(s),(r),(a))
OSErr ETLGetTLMIME(FSSpecPtr spec,emsMIMEHandle *tlMIME);
OSErr ETLCopyFile(FSSpecPtr spec,short refN,Boolean display,HeaderDHandle *theHeaders);
OSErr ETLReadTLMIME(FSSpecPtr spec,emsMIMEHandle *tlMIME);
OSErr ETLBuildOldAddrList(MessHandle messH,tlAddrListHandle *addrList,Boolean expandNicks);
static OSErr ETLTranslate(TLMHandle translators,short context,emsMIMEHandle emsMIME,FSSpecPtr source,emsMIMEHandle *emsMIMEOut,tlStringHandle *textOut,FSSpecPtr into,tlStringHandle *errorStr,long *errCode,emsHeaderDataP addrList);
static OSErr ETLTransOutLow(TLMHandle transList,emsHeaderDataP addrList,emsMIMEHandle tlMIME,FSSpecPtr from,FSSpecPtr to,MessHandle messH);
static void DisposeOldAddrList(tlAddrListHandle addrList);
OSErr ETLTransHandleBuf(UHandle *text,TLMPtr tlm);
static OSErr ETLTransHandleFile(UHandle *text,TLMPtr tlm,PETEHandle pte);
void ETLAboutButton(MyWindowPtr win,ControlHandle button,long modifiers,short part);
void ETLAboutUpdate(MyWindowPtr win);
Boolean ETLAboutClose(MyWindowPtr win);
Boolean ETLKey(MyWindowPtr win, EventRecord *event);
void ETLAboutClick(MyWindowPtr win, EventRecord *event);
static emsAddressH GetAddressesFromHandle(Uhandle text,Boolean expandNicks);
static emsAddressH FindAddress(Accumulator acc, short index,Boolean expandNicks);
OSErr ETLAddVolatileMenus(void);
#define SetSize(x) (x).size = sizeof(x);
static OSErr GetTransIcon(TLFLPtr tlfl,long id,Handle *suite);
static OSErr CanTranslateFile(TLFLPtr pTLFL,long context,short trans_id,
emsMIMEHandle in_mime,StringPtr **out_error,
long *out_code, StringPtr *queuedProperties, emsHeaderDataP header, MessHandle messH);
static OSErr MyTranslateFile(TLFLPtr pTLFL,long context,short trans_id,
emsMIMEHandle in_mime,FSSpec *in_file,emsMIMEHandle *out_mime,
FSSpec *out_file,Handle *out_icon,StringPtr **out_desc,StringPtr **out_error,
long *out_code, StringHandle queuedProperties, emsHeaderDataP header, MessHandle messH, Handle translatorName);
static tlMIMEtypeP DegradeMIME(emsMIMEHandle inMIME);
static emsMIMEHandle UpgradeMIME(tlMIMEtypeP inMIME);
static void DisposeOldTLMIME(tlMIMEtypeP tlMIME);
static void DisposeOldTLMIMEParam(tlMIMEParamP param);
static tlMIMEParamP DegradeMIMEParam(emsMIMEparamH hParam);
static OSErr NewMIME(emsMIMEHandle *tlMIME,short mimeType,short subType);
static StringHandle GetQueuedProperties(MessHandle messH,long id);
static emsAddressH MakeAddress(StringPtr sAddress,StringPtr sName);
static void ZapAddress(emsAddressH address);
static Boolean IsSystemComponent(Component comp);
static OSErr QueuedProperties(short which, long *selected, StringHandle *pProperties,Boolean fDefaultOn);
static void GetContextIconRect(Rect *rContentBox, Rect *rIcon);
static Boolean PluginIDToIndex(long key,short *index);
static void CheckAddToToolbar(TLMHandle hTLM, MenuHandle hMenu);
static emsAddressH GetAddressesFromHeader(UHandle textIn,short header,Boolean expandNicks);
#define ContextRequiresExpansion(context) (((context)&(EMSF_Q4_COMPLETION+EMSF_Q4_TRANSMISSION))!=0)
// Global variables
short gIdleTimeCount; // # of plug-ins that want idle time
long gPluginDrain;
unsigned long gTranslatorFlags; // All flags set by any translator
// List of components in System Folder. So we don't unregister
// any components installed a system startup time.
Component **ghSystemComponents;
// Callback function declarations and UPP's
typedef pascal short ETLProgressType(short percent);
SIMPLE_UPP(ETLProgress,tlProgress); // v1
typedef pascal short ETLProgress3Type(emsProgressDataP progData);
SIMPLE_UPP(ETLProgress3,emsProgress); // v3
typedef pascal void ETLGetMailboxType(emsGetMailBoxDataP getMailBoxData);
SIMPLE_UPP(ETLGetMailbox,emsGetMailBox); // v4
typedef pascal void ETLSetMailBoxTagType(emsSetMailBoxTagDataP setMailBoxTagData);
SIMPLE_UPP(ETLSetMailBoxTag,emsSetMailBoxTag);
typedef pascal void ETLGetMailBoxTagType(emsSetMailBoxTagDataP setMailBoxTagData);
SIMPLE_UPP(ETLGetMailBoxTag,emsGetMailBoxTag); // v5
typedef pascal short ETLGetPersonalityType(emsGetPersonalityDataP getPersonalityData);
SIMPLE_UPP(ETLGetPersonality,emsGetPersonality);
typedef pascal short ETLGetPersonalityInfoType(emsGetPersonalityInfoDataP getPersonalityData);
SIMPLE_UPP(ETLGetPersonalityInfo,emsGetPersonalityInfo);
typedef pascal void ETLRegenerateType(emsRegenerateDataP RegenerateData);
SIMPLE_UPP(ETLRegenerate,emsRegenerate);
typedef pascal short ETLGetDirectoryType(emsGetDirectoryDataP GetDirectoryData);
SIMPLE_UPP(ETLGetDirectory,emsGetDirectory);
typedef pascal void ETLUpdateWindowsType(void);
SIMPLE_UPP(ETLUpdateWindows,emsUpdateWindows);
typedef pascal short ETLPlugwindowRegisterType(emsPlugwindowDataP wd);
SIMPLE_UPP(ETLPlugwindowRegister,emsPlugwindowRegister);
typedef pascal void ETLPlugwindowUnRegisterType(emsPlugwindowDataP wd);
SIMPLE_UPP(ETLPlugwindowUnRegister,emsPlugwindowUnRegister);
typedef pascal void ETLGDeviceRgnType(emsGDeviceRgnDataP wd);
SIMPLE_UPP(ETLGDeviceRgn,emsGDeviceRgn);
typedef pascal void ETLSelectWindowType(WindowPtr wp);
SIMPLE_UPP(ETLSelectWindow,emsSelectWindow);
typedef pascal WindowPtr ETLFrontWindowType(void);
SIMPLE_UPP(ETLFrontWindow,emsFrontWindow);
typedef pascal short ETLMakeSigType(emsMakeSigDataP makeSigData);
SIMPLE_UPP(ETLMakeSig,emsMakeSig); // v6
typedef pascal short ETLMakeAddressBookType(emsMakeAddressBookDataP makeSigData);
SIMPLE_UPP(ETLMakeAddressBook,emsMakeAddressBook);
typedef pascal short ETLMakeABEntryType(emsMakeABEntryDataP makeABEntryData);
SIMPLE_UPP(ETLMakeABEntry,emsMakeABEntry);
typedef pascal short ETLMakeMailboxType(emsMakeMailboxDataP makeMailboxData);
SIMPLE_UPP(ETLMakeMailbox,emsMakeMailbox);
typedef pascal short ETLMakeOutMessType(emsMakeOutMessDataP makeOutMessData);
SIMPLE_UPP(ETLMakeOutMess,emsMakeOutMess);
typedef pascal short ETLMakeMessageType(emsMakeMessageDataP MakeMessageData);
SIMPLE_UPP(ETLMakeMessage,emsMakeMessage);
typedef pascal short ETLCreateMailBoxType(emsCreateMailBoxDataP createMailboxData);
SIMPLE_UPP(ETLCreateMailBox,emsCreateMailBox);
typedef pascal short ETLIsInAddressBookType(emsIsInAddressBookDataP isInAddressBookData);
SIMPLE_UPP(ETLIsInAddressBook,emsIsInAddressBook);
typedef pascal short ETLImportMboxType(emsImportMboxDataP importMBoxData);
SIMPLE_UPP(ETLImportMbox,emsImportMbox);
#define TO_UPP_OR_NOT_TO_UPP(proc) (HaveOSX() ? proc : proc##UPP)
// Use parameter-block style functions? (version 3+)
#define UseParameterBlockStyleFunctions(version) (version >= EMS_PB_VERSION)
// Use old mail config? (versions before 7)
#define UseOldMailConfig(version) (version < EMS_NEW_MAIL_CONFIG_VERSION)
/**********************************************************************
* Functions for managing modules
**********************************************************************/
// carbon build looks for 'ecTL' type plugins when running under OS X
#define TL_COMPONENT_TYPE (HaveOSX() ? 'ecTL' : 'euTL')
/**********************************************************************
* ETLOpenModules - open & count the translator modules
* Returns:
* # of translator modules
**********************************************************************/
short ETLOpenModules(AccuPtr instances)
{
ComponentDescription looking;
Component index=nil;
Component lastComponent=nil;
tlInstance instance;
Boolean retry;
if (!AccuInit(instances))
{
#ifdef DEBUG
#ifdef NO_EMSAPI_INIT
if (RunType!=Debugging)
#endif
#endif
do
{
Zero(looking);
looking.componentType = TL_COMPONENT_TYPE;
retry = False;
if (index = FindNextComponent(index, &looking))
{
if (instance=OpenComponent(index))
{
lastComponent = index;
AccuAddPtr(instances,(void*)&instance,sizeof(instance));
}
else
{
ASSERT(0);
UnregisterComponent(index);
index = lastComponent;
retry = True;
}
}
}
while(retry || index);
return(instances->offset/sizeof(instance));
}
return(0);
}
/**********************************************************************
* ETLGetSystemPlugins - get plugins that were already installed
* and record so we don't unregister them on cleanup
**********************************************************************/
void ETLGetSystemPlugins(void)
{
ComponentDescription looking;
Component index=nil;
do
{
Zero(looking);
looking.componentType = TL_COMPONENT_TYPE;
if (index = FindNextComponent(index, &looking))
{
// Need to add this to system component list
if (!ghSystemComponents) ghSystemComponents=NuHandle(0);
if (ghSystemComponents)
PtrAndHand(&index, (Handle)ghSystemComponents, sizeof(index));
}
}
while(index);
}
/**********************************************************************
* ETLDrain - how much memory do the plug-ins use?
**********************************************************************/
long ETLDrain(void)
{
return gPluginDrain;
}
/**********************************************************************
* Functions for individual modules
**********************************************************************/
ModeTypeEnum GetCurrentPayMode () {
if ( CanPayMode ()) return EMS_ModePaid;
if ( IsAdwareMode ()) return EMS_ModeSponsored;
if ( IsFreeMode ()) return EMS_ModeFree;
ASSERT ( false );
return EMS_ModeFree;
}
/**********************************************************************
* ETLInit - global translator initialization
**********************************************************************/
OSErr ETLInit()
{
short m, mCount;
short t;
short selItem=0,specItem=SPECIAL_BAR4_ITEM,attItem=0,setItem=0;
OSErr err = noErr;
Str255 s;
//Handle nHandle;
MenuHandle selMH = GetMHandle(TLATE_SEL_HIER_MENU);
MenuHandle setMH = GetMHandle(TLATE_SET_HIER_MENU);
MenuHandle specMH = GetMHandle(SPECIAL_MENU);
MenuHandle attMH = GetMHandle(TLATE_ATT_HIER_MENU);
TLMaster tlm;
TLFuncList tlfl;
Handle icon=nil;
//Boolean anIcon;
//short version;
Boolean menu;
Accumulator instances;
short realCount=0;
emsMIMEHandle tlMIME=nil;
OSErr looseErr;
struct emsMenuS emsMenuStuff;
emsPluginInfo pluginInfo;
gPluginDrain = 0;
if (TLSelList) {ETLAddAppleItem(); return(ETLAddVolatileMenus());}
TLSelList = NuHandle(0);
TLQ4List = NuHandle(0);
TLSpecialList = NuHandle(0);
TLAttachList = NuHandle(0);
TLSettingList = NuHandle(0);
TLModelessList = NuHandle(0);
TLImporterList = NuHandle(0);
TLFL = NuHandle(0);
Zero(instances);
NewMIME(&tlMIME,MIME_TEXT,MIME_PLAIN);
gTranslatorFlags = 0;
if (TLFL && TLModelessList && TLSelList && TLQ4List && TLSpecialList && TLAttachList && TLSettingList && TLImporterList &&
selMH && setMH && attMH && specMH && (mCount=ETLOpenModules(&instances)))
{
for (m=0;m<mCount;m++)
{
long drain,free,mem_rqmnt;
err = 0;
mem_rqmnt = 0;
free = FreeMem();
Zero(tlfl);
tlfl.instance = (*(ComponentInstance**)instances.data)[m];
#if defined(NEVER)
if (err = ems_plugin_version(tlfl.instance,&version))
{
// Older, version 1, plugin which doesn't have the version function. Version 3+ MUST implement the version function
version = 1;
err = 0;
}
#endif
tlfl.version = GetComponentVersion(tlfl.instance)>>16;
if (!err)
{
Zero(pluginInfo);
if (UseParameterBlockStyleFunctions(tlfl.version))
{
Zero(pluginInfo);
SetSize(pluginInfo);
if (UseOldMailConfig(tlfl.version))
{
emsPre7MailConfig mailConfig;
ETLFillMailConfig(&mailConfig, nil, true);
MightSwitch();
err = ems_plugin_init(tlfl.instance,EMS_VERSION,&mailConfig,&pluginInfo);
AfterSwitch();
ETLEmptyMailConfig(&mailConfig);
}
else
{
emsCallBack callbacks;
emsMailConfig mailConfig;
ETLFillMailConfig(&mailConfig, &callbacks, false);
MightSwitch();
err = ems_plugin_init(tlfl.instance,EMS_VERSION,&mailConfig,&pluginInfo);
AfterSwitch();
ETLEmptyMailConfig(&mailConfig);
}
tlfl.moduleDescription = pluginInfo.desc;
tlfl.moduleID = pluginInfo.id;
tlfl.moduleSuite = pluginInfo.icon;
tlfl.numMBoxContext = pluginInfo.numMBoxContext;
if (tlfl.idleTimeFreq = pluginInfo.idleTimeFreq)
{
tlfl.lastIdleTime = (TickCount()*50)/3; // (ticks / 60 * 1000) Roughly in milliseconds
gIdleTimeCount++;
}
tlfl.tCount = pluginInfo.numTrans;
mem_rqmnt = pluginInfo.mem_rqmnt;
}
else
{
MightSwitch();
err = tl_module_init(tlfl.instance,&tlfl.tCount,&tlfl.moduleDescription,&tlfl.moduleID,&tlfl.moduleSuite);
AfterSwitch();
}
}
// Make sure we get a name
if (!tlfl.moduleDescription)
{
ComponentDescription cd;
if (tlfl.moduleDescription = NuHandle(0))
{
GetComponentInfo(tlfl.instance,&cd,tlfl.moduleDescription,nil,nil);
if (!GetHandleSize(tlfl.moduleDescription)) ZapHandle(tlfl.moduleDescription);
}
}
// Ugly hack time
if (tlfl.moduleID==29 || tlfl.moduleID==31) tlfl.modeNeeded = EMS_ModePaid;
//if (!err && version!=TL_VERSION) ETLError(moduleDescription,ETL_BAD_VERSION,nil,version,0);
//else
if (err)
{
ETLError(tlfl.moduleDescription,ETL_CANT_INIT,nil,err,0);
UnregisterComponent(tlfl.instance);
}
else if (!(err = PtrPlusHand_(&tlfl,TLFL,sizeof(tlfl))))
{
if (ComponentFunctionImplemented(tlfl.instance,kems_plugin_configRtn))
{
tlm.menuItem = ++setItem;
tlm.module = realCount;
PtrPlusHand_(&tlm,TLSettingList,sizeof(tlm));
PCopy(s,*tlfl.moduleDescription);
PCat(s,"\p...");
MyAppendMenu(setMH,s);
}
// translators
for (t=0;t<tlfl.tCount;t++)
{
Zero(tlm);
// v3
if (UseParameterBlockStyleFunctions(tlfl.version))
{
emsTranslator transInfo;
Zero(transInfo);
SetSize(transInfo);
transInfo.id = t+1;
MightSwitch();
err = ems_translator_info(tlfl.instance,&transInfo);
AfterSwitch();
tlm.type = transInfo.type;
tlm.flags = transInfo.flags;
tlm.nameHandle = transInfo.desc;
tlm.suite = transInfo.icon;
}
// v1
else
{
MightSwitch();
err = tl_translator_info(tlfl.instance,t+1,&tlm.type,nil,&tlm.flags,&tlm.nameHandle,&tlm.suite);
AfterSwitch();
}
if (!err)
{
gTranslatorFlags |= tlm.flags;
menu = (tlm.flags & TLF_ON_REQUEST);
if (menu) tlm.menuItem = ++selItem;
tlm.module = realCount;
tlm.id = t+1;
err = PtrPlusHand_(&tlm,TLSelList,sizeof(tlm));
if (err) ZapHandle(tlm.nameHandle);
if (tlm.suite && (tlm.flags&(EMSF_Q4_TRANSMISSION)) &&
(tlm.flags&TLF_WHOLE_MESSAGE))
PtrPlusHand_(&tlm,TLQ4List,sizeof(tlm));
if (!ComponentFunctionImplemented(tlfl.instance,kems_plugwindow_closeRtn))
PtrPlusHand_(&tlm,TLModelessList,sizeof(tlm));
if (!LooseTrans)
{
looseErr = CanTranslateFile(&tlfl,TLF_ON_ARRIVAL,tlm.id,tlMIME,
nil,nil,nil,nil,nil);
LooseTrans = looseErr==TLR_NOW || looseErr==TLR_NOT_NOW;
}
}
}
// attachers
for (t=0;t<pluginInfo.numAttachers;t++)
{
Zero(emsMenuStuff); SetSize(emsMenuStuff);
emsMenuStuff.id = t;
if (!(err=!ComponentFunctionImplemented(tlfl.instance,kems_attacher_infoRtn)))
{
MightSwitch();
err=ems_attacher_info(tlfl.instance,&emsMenuStuff);
AfterSwitch();
if (!err)
{
if (emsMenuStuff.desc)
{
Zero(tlm);
tlm.id = t;
tlm.module = realCount;
tlm.menuItem = ++attItem;
tlm.nameHandle = emsMenuStuff.desc;
tlm.flags = emsMenuStuff.flags;
PtrPlusHand_(&tlm,TLAttachList,sizeof(tlm));
MyAppendMenu(attMH,PCopy(s,*tlm.nameHandle));
}
if (emsMenuStuff.icon)
DisposeIconSuite(emsMenuStuff.icon,true);
}
}
}
// specials
for (t=0;t<pluginInfo.numSpecials;t++)
{
Zero(emsMenuStuff); SetSize(emsMenuStuff);
emsMenuStuff.id = t;
if (!(err=!ComponentFunctionImplemented(tlfl.instance,kems_special_infoRtn)))
{
MightSwitch();
err=ems_special_info(tlfl.instance,&emsMenuStuff);
AfterSwitch();
if (!err)
{
if (emsMenuStuff.desc)
{
Zero(tlm);
tlm.id = t;
tlm.module = realCount;
tlm.menuItem = ++specItem;
tlm.nameHandle = emsMenuStuff.desc;
tlm.flags = emsMenuStuff.flags;
PtrPlusHand_(&tlm,TLSpecialList,sizeof(tlm));
}
if (emsMenuStuff.icon)
DisposeIconSuite(emsMenuStuff.icon,true);
}
}
}
// search for any importers
for (t=0;(t<pluginInfo.numImporters);t++)
{
emsImporter importerInfo;
Zero(importerInfo);
SetSize(importerInfo);
importerInfo.id = t+1;
if (!(err=!ComponentFunctionImplemented(tlfl.instance,kems_importer_infoRtn)))
{
MightSwitch();
err=ems_importer_info(tlfl.instance,&importerInfo);
AfterSwitch();
if (!err)
{
if (importerInfo.desc)
{
Zero(tlm);
tlm.id = t;
tlm.module = realCount;
tlm.nameHandle = importerInfo.desc;
tlm.flags = importerInfo.flags;
tlm.suite = importerInfo.icon;
PtrPlusHand_(&tlm,TLImporterList,sizeof(tlm));
}
gImportersAvailable = true; // remember that at least one importer has been found
}
}
}
err = 0;
realCount++;
}
// Calculate memory used by this plug-in. Use the greater of:
// 1) actualy memory used, 2) memory use as reported by the plug-in
drain = free - FreeMem();
gPluginDrain += drain>mem_rqmnt ? drain : mem_rqmnt;
}
// Notify all plugins that care of the current mode
ETLEudoraModeNotification(EMS_ModeChanged, GetCurrentPayMode ());
}
GetRString(s,NO_TRANSLATORS);
#define NO_TRANS(x) do{if (!x##Item) {MyAppendMenu(x##MH,s);SetItemStyle(x##MH,1,italic);DisableItem(x##MH,1);}}while(0)
NO_TRANS(sel);
NO_TRANS(att);
if (realCount) GetRString(s,NO_TRANSLATORS_WITH_SETTINGS);
NO_TRANS(set);
ETLAddVolatileMenus();
AccuZap(instances);
ZapTLMIME(tlMIME);
if (!realCount) {ZapHandle(TLFL);ZapHandle(TLSelList);ZapHandle(TLQ4List);ZapHandle(TLSpecialList);ZapHandle(TLAttachList);ZapHandle(TLImporterList);}
else ETLAddAppleItem();
return(realCount ? noErr : fnfErr);
}
/************************************************************************
* ETLAddToToolbar - add any translators, attachers or special items
* to the toolbar that are requesting it
************************************************************************/
static void CheckAddToToolbar(TLMHandle hTLM, MenuHandle hMenu)
{
short i,n;
Str255 s;
short oldRefN = CurResFile();
typedef struct TLMaster
{
short moduleID;
short menuID;
Str32 itemText;
} TBIconList, *TBIconListPtr, **TBIconListHandle;
if (hMenu && hTLM && *hTLM && (n=HandleCount(hTLM)))
{
for (i=0;i<n;i++)
{
if ((*hTLM)[i].flags & EMSF_TOOLBAR_PRESENCE)
{
// Put this arrogant translator in the toolbar
Boolean doAdd;
TBIconListHandle hAddedList;
TBIconListPtr pAddedList;
short menuID = GetMenuID(hMenu);
short moduleID = (*TLFL)[(*hTLM)[i].module].moduleID;
// Make sure we haven't added it before
doAdd = true;
PCopy(s,*(*hTLM)[i].nameHandle);
if (*s>31) *s=31;
UseResFile(SettingsRefN);
if (hAddedList = (TBIconListHandle)Get1Resource(TOOLBAR_ICON_RTYPE,TOOLBAR_ICON_ID))
{
short count;
for(pAddedList=*hAddedList,count=HandleCount(hAddedList);count--;pAddedList++)
{
if (pAddedList->moduleID==moduleID && pAddedList->menuID==menuID && StringSame(pAddedList->itemText,s))
{
// We've previously added this one. Once is enough!
doAdd = false;
break;
}
}
}
if (doAdd && TBAddMenuButton(menuID,(*hTLM)[i].menuItem,s))
{
TBIconList iconListItem;
// Add to list of items already added
Zero(iconListItem);
iconListItem.moduleID = moduleID;
iconListItem.menuID = menuID;
PCopy(iconListItem.itemText,s);
if (!hAddedList)
{
// Need to create new resource
hAddedList = NuHandle(0);
AddResource_(hAddedList,TOOLBAR_ICON_RTYPE,TOOLBAR_ICON_ID,"");
}
PtrAndHand(&iconListItem,(Handle)hAddedList,sizeof(iconListItem));
ChangedResource((Handle)hAddedList);
}
}
}
}
UseResFile(oldRefN);
}
/************************************************************************
* ETLAddToToolbar - add any translators, attachers or special items
* to the toolbar that are requesting it
************************************************************************/
void ETLAddToToolbar(void)
{
CheckAddToToolbar(TLSelList,GetMHandle(TLATE_SEL_HIER_MENU));
CheckAddToToolbar(TLAttachList,GetMHandle(TLATE_ATT_HIER_MENU));
CheckAddToToolbar(TLSpecialList,GetMHandle(SPECIAL_MENU));
}
/************************************************************************
* ETLAddVolatileMenus - add trans items to menus that need to be refreshed
* when switching settings files
************************************************************************/
OSErr ETLAddVolatileMenus(void)
{
MenuHandle specMH = GetMHandle(SPECIAL_MENU);
MenuHandle selMH = GetMHandle(TLATE_SEL_HIER_MENU);
short i,n;
Str255 s;
if (specMH && TLSpecialList && *TLSpecialList && (n=HandleCount(TLSpecialList)))
{
AppendMenu(specMH,"\p-");
for (i=0;i<n;i++)
MyAppendMenu(specMH,PCopy(s,*(*TLSpecialList)[i].nameHandle));
}
if (selMH && TLSelList && *TLSelList && (n=HandleCount(TLSelList)))
{
for (i=0;i<n;i++)
if ((*TLSelList)[i].flags & TLF_ON_REQUEST)
MyAppendMenu(selMH,PCopy(s,*(*TLSelList)[i].nameHandle));
}
return(noErr);
}
/************************************************************************
* ETLFillMailConfig - fill a mailconfig
************************************************************************/
void ETLFillMailConfig(emsMailConfigP mailConfig, emsCallBacksP callBacks, Boolean useOldMailConfig)
{
Str255 scratch;
// Account for differences between old and new mail config structures
if (useOldMailConfig)
{
emsPre7MailConfigP oldMailConfig = (emsPre7MailConfigP) mailConfig;
Zero(*oldMailConfig);
SetSize(*oldMailConfig);
// Old mail config structure accidently had callbacks directly in the structure
callBacks = &oldMailConfig->callBacks;
}
else
{
Zero(*mailConfig);
SetSize(*mailConfig);
// New mail config structure has pointer to callbacks so that we can have fields
// after the callbacks.
mailConfig->callBacks = callBacks;
// For a while we had eudAPIMinorVersion in the old structure, but the location became
// obsolete as more callbacks were added. Now we only support it in the new structure.
mailConfig->eudAPIMinorVersion = EMS_MINOR_VERSION;
}
// From here on out we've already accounted for all the differences
FSMakeFSSpec(ItemsFolder.vRef,ItemsFolder.dirId,GetRString(scratch,PLUGINS_FOLDER),&mailConfig->configDir);
SetSize(mailConfig->userAddr);
mailConfig->userAddr.address = NewString(GetReturnAddr(scratch,false));
mailConfig->userAddr.realname = NewString(GetRealname(scratch));
// v4 stuff
callBacks->EMSGetMailBoxFunction = TO_UPP_OR_NOT_TO_UPP(ETLGetMailbox);
callBacks->EMSSetMailBoxTagFunction = TO_UPP_OR_NOT_TO_UPP(ETLSetMailBoxTag);
callBacks->EMSGetPersonalityFunction = TO_UPP_OR_NOT_TO_UPP(ETLGetPersonality);
callBacks->EMSProgressFunction = TO_UPP_OR_NOT_TO_UPP(ETLProgress3);
callBacks->EMSRegenerateFunction = TO_UPP_OR_NOT_TO_UPP(ETLRegenerate);
callBacks->EMSGetDirectoryFunction = TO_UPP_OR_NOT_TO_UPP(ETLGetDirectory);
callBacks->EMSUpdateWindowsFunction = TO_UPP_OR_NOT_TO_UPP(ETLUpdateWindows);
// v5 stuff
callBacks->EMSGetMailBoxTagFunction = TO_UPP_OR_NOT_TO_UPP(ETLGetMailBoxTag);
callBacks->EMSGetPersonalityInfoFunction = TO_UPP_OR_NOT_TO_UPP(ETLGetPersonalityInfo);
callBacks->EMSPlugwindowRegisterFunction = TO_UPP_OR_NOT_TO_UPP(ETLPlugwindowRegister);
callBacks->EMSPlugwindowUnRegisterFunction = TO_UPP_OR_NOT_TO_UPP(ETLPlugwindowUnRegister);
callBacks->EMSGDeviceRgnFunction = TO_UPP_OR_NOT_TO_UPP(ETLGDeviceRgn);
callBacks->EMSFrontWindowFunction = TO_UPP_OR_NOT_TO_UPP(ETLFrontWindow);
callBacks->EMSSelectWindowFunction = TO_UPP_OR_NOT_TO_UPP(ETLSelectWindow);
// v6 stuff
callBacks->EMSMakeSigFunction = TO_UPP_OR_NOT_TO_UPP(ETLMakeSig);
callBacks->EMSMakeAddressBookFunction = TO_UPP_OR_NOT_TO_UPP(ETLMakeAddressBook);
callBacks->EMSMakeABEntryFunction = TO_UPP_OR_NOT_TO_UPP(ETLMakeABEntry);
callBacks->EMSMakeMailboxFunction = TO_UPP_OR_NOT_TO_UPP(ETLMakeMailbox);
callBacks->EMSMakeOutMessFunction = TO_UPP_OR_NOT_TO_UPP(ETLMakeOutMess);
callBacks->EMSMakeMessageFunction = TO_UPP_OR_NOT_TO_UPP(ETLMakeMessage);
callBacks->EMSCreateMailBoxFunction = TO_UPP_OR_NOT_TO_UPP(ETLCreateMailBox);
// v7 stuff
callBacks->EMSIsInAddressBook = TO_UPP_OR_NOT_TO_UPP(ETLIsInAddressBook);
}
/************************************************************************
* ETLEmptyMailConfig - empty the mailconfig
************************************************************************/
void ETLEmptyMailConfig(emsMailConfigP mailConfig)
{
ZapHandle(mailConfig->userAddr.address);
ZapHandle(mailConfig->userAddr.realname);
}
/**********************************************************************
*
**********************************************************************/
void ETLAddAppleItem(void)
{
Str255 s;
MenuHandle mh = GetMHandle(APPLE_MENU);
InsertMenuItem(mh,GetRString(s,ABOUT_TRANSLATORS),1);
}
/**********************************************************************
*
**********************************************************************/
Boolean ETLExists(void)
{
return(TLFL!=nil);
}
/**********************************************************************
* ETLDoAbout - give Laurence his darn about translators window
**********************************************************************/
void ETLDoAbout(void)
{
short n = HandleCount(TLFL);
MyWindowPtr win;
WindowPtr winWP;
ControlHandle cntl;
ListHandle list;
Rect r,bounds;
Point c;
DECLARE_UPP(TlateListDef,ListDef);
INIT_UPP(TlateListDef,ListDef);
if (ModalWindow) return; // already a window onscreen
if (win=GetNewMyWindow(ETL_ABOUT_WIND,nil,nil,nil,False,False,ETL_ABOUT_WIN))
{
winWP = GetMyWindowWindowPtr (win);
win->position = PositionPrefsTitle;
win->isRunt = True;
win->button = ETLAboutButton;
win->update = ETLAboutUpdate;
win->close = ETLAboutClose;
win->click = ETLAboutClick;
win->key = ETLKey;
win->dontControl = True;
MySetThemeWindowBackground(win,kThemeListViewBackgroundBrush,False);
SetRect(&r,2*INSET,2*INSET,win->contR.right-INSET-GROW_SIZE,win->contR.bottom-20-3*INSET);
SetRect(&bounds,0,0,1,n);
c.v = 38;
c.h = RectWi(r);
if (!(list = CreateNewList(TlateListDefUPP,TLATE_LDEF,&r,&bounds,c,winWP,True,False,False,True)))
CloseMyWindow(winWP);
else
{
(*list)->indent.h = INSET;
cntl = GetNewControl(ETL_OK_CNTL,winWP);
SetControlReference(cntl,'OKbn');
if (!cntl) CloseMyWindow(winWP);
else
{
MoveMyCntl(cntl,win->contR.right-INSET-ControlWi(cntl),
win->contR.bottom-INSET-ControlHi(cntl),0,0);
SetMyWindowPrivateData (win,(long)list);
ShowMyWindow(winWP);
PushModalWindow(winWP);
}
}
}
}
/**********************************************************************
* ETLAboutClick - handle clicks
**********************************************************************/
void ETLAboutClick(MyWindowPtr win, EventRecord *event)
{
Point mouse = event->where;
Rect listR = (*(ListHandle)GetMyWindowPrivateData(win))->rView;
GlobalToLocal(&mouse);
listR.right += GROW_SIZE;
if (PtInRect(mouse,&listR)) LClick(mouse,event->modifiers,(ListHandle)GetMyWindowPrivateData(win));
else HandleControl(mouse,win);
}
/**********************************************************************
* ETLAboutButton - shows button
**********************************************************************/
void ETLAboutButton(MyWindowPtr win,ControlHandle button,long modifiers,short part)
{
#pragma unused(button)
WindowPtr winWP = GetMyWindowWindowPtr (win);
if (part==kControlButtonPart) CloseMyWindow(winWP);
AuditHit((modifiers&shiftKey)!=0, (modifiers&controlKey)!=0, (modifiers&optionKey)!=0, (modifiers&cmdKey)!=0, false, GetWindowKind(winWP), AUDITCONTROLID(GetWindowKind(winWP),kControlButtonPart), mouseDown);
}
/**********************************************************************
* ETLAboutClose - close the window
**********************************************************************/
Boolean ETLAboutClose(MyWindowPtr win)
{
if (GetMyWindowPrivateData(win))
{
LDispose((ListHandle)GetMyWindowPrivateData(win));
SetMyWindowPrivateData(win, 0);
}
return(True);
}
/**********************************************************************
*
**********************************************************************/
Boolean ETLKey(MyWindowPtr win, EventRecord *event)
{
#pragma unused(event)
short c = (event->message & charCodeMask);
if (c==enterChar || c==returnChar || c==escChar) CloseMyWindow(GetMyWindowWindowPtr(win));
return(True);
}
/**********************************************************************
* ETLAboutUpdate - update the window
**********************************************************************/
void ETLAboutUpdate(MyWindowPtr win)
{
WindowPtr winWP = GetMyWindowWindowPtr(win);
Rect r;
ControlHandle cntl = FindControlByRefCon(win,'OKbn');
if (GetMyWindowPrivateData(win))
{
r = (*(ListHandle)GetMyWindowPrivateData(win))->rView;
r.right += GROW_SIZE;
DrawThemeListBoxFrame(&r,kThemeStateActive);
LUpdate(MyGetPortVisibleRegion(GetWindowPort(winWP)),(ListHandle)GetMyWindowPrivateData(win));
if (cntl)
OutlineControl(cntl,True);
}
}
/**********************************************************************
* ETLMenu2Icon - get icon suite for plug-in menu selection
**********************************************************************/
Handle ETLMenu2Icon(short menu,short item)
{
short n;
TLMaster tlm;
Handle suite = nil;
Boolean gotModule = false;
emsMenu emsMenuStuff;
OSErr err;
switch (menu)
{
case TLATE_SEL_HIER_MENU:
for(n=HandleCount(TLSelList);n--;)
if ((*TLSelList)[n].menuItem==item)
{
tlm = (*TLSelList)[n];
GetTransIcon(&(*TLFL)[tlm.module],tlm.id,&suite);
gotModule = true;
break;
}
break;
case SPECIAL_MENU:
case TLATE_ATT_HIER_MENU:
if (menu == SPECIAL_MENU)
{
if (item>SPECIAL_BAR4_ITEM)
{
tlm = (*TLSpecialList)[item-SPECIAL_BAR4_ITEM-1];
gotModule = true;
}
}
else
{
tlm = (*TLAttachList)[item-1];
gotModule = true;
}
if (gotModule)
{
Zero(emsMenuStuff); SetSize(emsMenuStuff);
emsMenuStuff.id = tlm.id;
MightSwitch();
if (menu == SPECIAL_MENU)
err=ems_special_info((*TLFL)[tlm.module].instance,&emsMenuStuff);
else
err=ems_attacher_info((*TLFL)[tlm.module].instance,&emsMenuStuff);
AfterSwitch();
if (!err)
{
suite = emsMenuStuff.icon;
if (emsMenuStuff.desc)
DisposeHandle((Handle)emsMenuStuff.desc);
}
}
break;
}
if (gotModule && !suite)
{
Handle moduleSuite;
// Use module's icon
if (moduleSuite = (*TLFL)[tlm.module].moduleSuite)
DupIconSuite(moduleSuite,&suite,false);
}
return suite;
}
/**********************************************************************
* ETLListAllTranslators - list all the translators appropriate to a given context
* translators - pointer to handle to translator list; will be allocated
* context - the translator context (eg, tlOnArrival)
* Returns:
* TLR_CANT_TRANS - no translators for current context
* noErr - found at least one translator
**********************************************************************/
OSErr ETLListAllTranslatorsLo(TLMHandle *translators, short context, ModeTypeEnum forMode)
{
short i, n;
if (!TLSelList) return(TLR_CANT_TRANS);
n = HandleCount(TLSelList);
*translators = (TLMHandle)NuHTempBetter((n+1)*sizeof(TLMaster));
if (!*translators) return(MemError());
n = 0;
for (i=HandleCount(TLSelList);i--;)
if (((*TLSelList)[i].flags & context) && (*TLFL)[(*TLSelList)[i].module].modeNeeded<=forMode)
{
(**translators)[n] = (*TLSelList)[i];
n++;
}
if (!n)
{
ZapHandle(*translators);
return(TLR_CANT_TRANS);
}
else
{
SetHandleBig_(*translators,(n+1)*sizeof(TLMaster));
(**translators)[n].module = REAL_BIG;
(**translators)[n].result = REAL_BIG;
return(noErr);
}
}
/************************************************************************
* ETLCountTranslators - count the translators that work in a context & current mode
************************************************************************/
OSErr ETLCountTranslatorsLo(short context,ModeTypeEnum forMode)
{
TLMHandle tList = nil;
short count = 0;
(void) ETLListAllTranslatorsLo ( &tList, context, forMode );
if (tList)
{
count = HandleCount(tList)-1;
count = MAX(count,0);
ZapHandle(tList);
}
return count;
}
/**********************************************************************
* ETLRemoveDeadTranslators - remove translators that have been used or
* will never be used
* translators - handle to list of translators
* Returns:
* TLR_CANT_TRANS - if no live translators remain
**********************************************************************/
OSErr ETLRemoveDeadTranslators(TLMHandle translators)
{
short n = HandleCount(translators);
short from, to;
for (from=to=0;from<n;from++)
switch((*translators)[from].result)
{
case TLR_NOT_NOW:
case TLR_NOW:
if (to!=from) (*translators)[to] = (*translators)[from];
to++;
break;
}
if (to<n) SetHandleBig_(translators,to*sizeof(TLMaster));
return to > 0 ? noErr : TLR_CANT_TRANS;
}
/**********************************************************************
* ETLSortTranslators - sort translators by module and group
* translators - handle to translator list to sort
**********************************************************************/
void ETLSortTranslators(TLMHandle translators)
{
short n = HandleCount(translators);
QuickSort((void*)LDRef(translators),sizeof(TLMaster),0,n-2,(void*)ETLCompare,(void*)ETLSwap);
UL(translators);
}
/**********************************************************************
* ETLCompare - compare two translators
**********************************************************************/
int ETLCompare(TLMPtr t1,TLMPtr t2)
{
long diff;
if (diff=(t1->result-t2->result)) return(diff);
if (diff=(t1->type-t2->type)) return(diff);
if (diff=(t1->module-t2->module)) return(diff);
return(0);
}
/**********************************************************************
* ETLSwap - swap two translators
**********************************************************************/
void ETLSwap(TLMPtr t1,TLMPtr t2)
{
TLMaster t;
t = *t1;
*t1 = *t2;
*t2 = t;
}
/**********************************************************************
* ETLListRequestedTranslators - make a translator list from the messages
**********************************************************************/
OSErr ETLListRequestedTranslators(TLMHandle *translators, TransInfoHandle hRequested)
{
short i, n, index;
//Boolean canDo;
short nReq;
if (!TLSelList && !hRequested) return(TLR_CANT_TRANS);
nReq = HandleCount(hRequested);
*translators = (TLMHandle)NuHTempBetter((nReq+1)*sizeof(TLMaster));
if (!*translators) return(MemError());
n = 0;
for (i=0;i<nReq;i++)
{
index = ETLIDToIndex((*hRequested)[i].id);
if (index<0)
{
WarnUser(ETL_CANT_FIND_TRANS,0);
n = 0;
break;
}
(**translators)[n] = (*TLQ4List)[index];
n++;
}
if (!n)
{
ZapHandle(*translators);
return(TLR_CANT_TRANS);
}
else
{
SetHandleBig_(*translators,(n+1)*sizeof(TLMaster));
(**translators)[n].module = REAL_BIG;
(**translators)[n].result = REAL_BIG;
ETLSortTranslators(*translators);
for (i=0;i<n-1;i++)
{
if ((**translators)[i].type==TLT_SIGNATURE && (**translators)[i+1].type==TLT_PREPROCESS)
{
short bigI = HandleCount(TLSelList);
while (bigI--)
{
if ((*TLSelList)[bigI].module==(**translators)[i].module &&
(*TLSelList)[bigI].type==TLT_COALESCED)
{
(**translators)[i] = (*TLSelList)[bigI];
for (i++;i<n;i++) (**translators)[i] = (**translators)[i+1];
SetHandleBig_(*translators,n*sizeof(TLMaster));
return(noErr);
}
}
}
}
return(noErr);
}
}
/**********************************************************************
* ETLOutputHandle - output a handle to a file or accumulator (or nowhere)
**********************************************************************/
OSErr ETLOutputHandle(UHandle text,short refN,AccuPtr a)
{
OSErr err=noErr;
if (refN)
{
long size = GetHandleSize(text);
err = AWrite(refN,&size,LDRef(text));
UL(text);
}
else if (a) err = AccuAddHandle(a,text);
return(err);
}
/**********************************************************************
* ETLOutputPtr - output a pointer to a file or accumulator (or nowhere)
**********************************************************************/
OSErr ETLOutputPtr(UPtr text,long size,short refN,AccuPtr a)
{
OSErr err = noErr;
long locSize = size;
if (refN) err = AWrite(refN,&locSize,text);
else if (a) err = AccuAddPtr(a,text,size);
return(err);
}
/**********************************************************************
* progress callbacks
**********************************************************************/
// support ems api 1.0
static pascal short ETLProgress(short percent)
{
PushGWorld();
SetPort_(InsurancePort);
CycleBalls();
if (percent!=-1) Progress(percent,NoChange,nil,nil,nil);
PopGWorld();
return(CommandPeriod);
}
// support ems api 3.0
static pascal short ETLProgress3(emsProgressDataP progData)
{
short percent = -1;
PStr message = nil;
if (progData) {
percent = progData->value;
message = progData->message;
}
PushGWorld();
SetPort_(InsurancePort);
CycleBalls();
if (percent!=-1) Progress(percent,NoChange,nil,nil,message);
PopGWorld();
return(CommandPeriod);
}
/**********************************************************************
* ETLGetMailbox - allow user to select a mailbox
**********************************************************************/
static pascal void ETLGetMailbox(emsGetMailBoxDataP pData)
{
FSSpec spec;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
pData->mailbox = nil;
if (ChooseMailboxLo(MAILBOX_MENU,pData->prompt,&spec,!(pData->flags&EMSFGETMBOX_ALLOW_NEW),!(pData->flags&EMSFGETMBOX_ALLOW_OTHER),(pData->flags&EMSFGETMBOX_DISALLOW_NON_LOCAL)))
{
// Return alias to mailbox
FSSpec mailFolderSpec;
// Alias is relative to mail folder
FSMakeFSSpec(MailRoot.vRef, MailRoot.dirId, "", &mailFolderSpec);
NewAlias(&mailFolderSpec, &spec, &pData->mailbox);
}
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
}
/**********************************************************************
* ETLGetMailBoxTag - get tag ID for a mailbox
**********************************************************************/
static pascal void ETLGetMailBoxTag(emsSetMailBoxTagDataP pData)
{
FSSpec spec,mailFolderSpec;
TOCHandle tocH;
Boolean wasChanged;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
pData->oldkey = pData->oldvalue = 0;
// Alias is relative to mail folder
FSMakeFSSpec(MailRoot.vRef, MailRoot.dirId, "", &mailFolderSpec);
if (!ResolveAlias(&mailFolderSpec, pData->mailbox, &spec, &wasChanged))
{
// get key from mailbox's TOC
if (!GetTOCByFSS(&spec,&tocH))
{
pData->oldkey = (*tocH)->pluginKey;
pData->oldvalue = (*tocH)->pluginValue;
}
}
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
}
/**********************************************************************
* ETLSetMailBoxTag - set tag ID for a mailbox
**********************************************************************/
static pascal void ETLSetMailBoxTag(emsSetMailBoxTagDataP pData)
{
FSSpec spec,mailFolderSpec;
TOCHandle tocH;
Boolean wasChanged;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
// Alias is relative to mail folder
FSMakeFSSpec(MailRoot.vRef, MailRoot.dirId, "", &mailFolderSpec);
if (!ResolveAlias(&mailFolderSpec, pData->mailbox, &spec, &wasChanged))
{
// Add key to mailbox's TOC
if (!GetTOCByFSS(&spec,&tocH))
{
if (pData->size>=sizeof(*pData))
pData->oldkey = (*tocH)->pluginKey;
(*tocH)->pluginKey = pData->key;
pData->oldvalue = (*tocH)->pluginValue;
(*tocH)->pluginValue = pData->value;
TOCSetDirty(tocH,true);
if ((*tocH)->win)
{
Rect rOldSize;
GetPortBounds(GetMyWindowCGrafPtr((*tocH)->win),&rOldSize);
MyWindowDidResize((*tocH)->win,&rOldSize);
}
}
}
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
}
/************************************************************************
* ETLPlugwindowRegister - tell Eudora that a window belongs to a plug-in
************************************************************************/
pascal short ETLPlugwindowRegister(emsPlugwindowDataP wd)
{
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
{
WindowPtr theWindow = wd->nativeWindow;
emsPlugwindowDataH wdh = NewH(emsPlugwindowData);
if (!wdh) return(MemError());
**wdh = *wd;
SetWRefCon(theWindow,(long)wdh);
SetWindowKind(theWindow,EMS_PW_WINDOWKIND);
if (IsModalPlugwindow(theWindow))
PushModalWindow(theWindow);
}
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return(noErr);
}
/************************************************************************
* ETLPlugwindowUnRegister - tell Eudora that a window is dying
************************************************************************/
pascal void ETLPlugwindowUnRegister(emsPlugwindowDataP wd)
{
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
{
WindowPtr theWindow = wd->nativeWindow;
Handle theHandle = (Handle) GetWRefCon (theWindow);
if (theHandle != nil)
{
// Double check before calling PopModalWindow so that we're
// not at the mercy of a broken plugin.
if (IsModalPlugwindow(theWindow) && (theWindow == ModalWindow))
PopModalWindow();
ZapHandle(theHandle);
SetWRefCon(theWindow,nil);
}
#ifdef FLOAT_WIN
if (theWindow == lastHilitedWinWP) lastHilitedWinWP = 0;
#endif //FLOAT_WIN
}
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
}
/************************************************************************
* ETLGDeviceRgn - give plug-in device rgn
************************************************************************/
pascal void ETLGDeviceRgn(emsGDeviceRgnDataP gdr)
{
GDHandle gd;
Rect r;
Boolean hasMB = true;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
GetQDGlobalsScreenBitsBounds(&r);
utl_GetIndGD(gdr->gdIndex, &gd, &r, &hasMB);
InsetRect(&r,2,4);
r.left += GetRLong(DESK_LEFT_STRIP);
r.right -= GetRLong(DESK_RIGHT_STRIP);
r.bottom -= GetRLong(DESK_BOTTOM_STRIP);
r.top += GetRLong(DESK_TOP_STRIP);
if (hasMB)
r.top += utl_GetMBarHeight();
RectRgn(gdr->usableRgn,&r);
gdr->largestRectangle = r;
if (ToolbarSect(&r))
{
ToolbarReduce(&r);
gdr->largestRectangle = r;
ToolbarRect(&r);
RgnMinusRect(gdr->usableRgn,&r);
}
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
}
/**********************************************************************
* ETLFrontWindow - return the front window as Eudora thinks of it
**********************************************************************/
pascal WindowPtr ETLFrontWindow(void)
{
return MyFrontNonFloatingWindow();
}
/**********************************************************************
* ETLSelectWindow - SelectWindow our way
**********************************************************************/
pascal void ETLSelectWindow(WindowPtr wp)
{
if (wp) SelectWindow_(wp);
}
/**********************************************************************
* GetContextIconRect - get rect of context menu icon
**********************************************************************/
static void GetContextIconRect(Rect *rContentBox, Rect *rIcon)
{
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
*rIcon = *rContentBox;
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
}
/**********************************************************************
* PluginIDToIndex - find plug-in by module id
**********************************************************************/
static Boolean PluginIDToIndex(long key,short *index)
{
short i;
if (TLFL && key)
{
for (i=HandleCount(TLFL);i--;)
{
if ((*TLFL)[i].moduleID==key)
{
*index = i;
return true;
}
}
}
return false;
}
/**********************************************************************
* ETLDrawBoxTag - draw context menu if mailbox has plug-in tag
**********************************************************************/
void ETLDrawBoxTag(TOCHandle tocH,Rect *r)
{
short idx;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
if (PluginIDToIndex((*tocH)->pluginKey,&idx))
{
Rect rIcon;
IconTransformType transform = ttNone;
MyWindowPtr win = (*tocH)->win;
GetContextIconRect(r, &rIcon);
//FrameRect(&rIcon);
if (win && !win->isActive) transform = ttDisabled;
PlotIconSuite(&rIcon,atNone,transform,(*TLFL)[idx].moduleSuite);
}
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
}
/**********************************************************************
* ETLBoxTagWidth - return width of context menu icon
**********************************************************************/
short ETLBoxTagWidth(MyWindowPtr win)
{
short width = 0;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
{
TOCHandle tocH = (TOCHandle) GetMyWindowPrivateData(win);
if (tocH && (*tocH)->pluginKey)
width = 16;
}
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return width;
}
/**********************************************************************
* ETLAddBoxButtons - add the buttons to a peanut mailbox
**********************************************************************/
void ETLAddBoxButtons(TOCHandle tocH)
{
WindowPtr winWP = GetMyWindowWindowPtr((*tocH)->win);
short idx;
short item;
if (PluginIDToIndex((*tocH)->pluginKey,&idx) && (*tocH)->win->topMarginCntl)
{
tlInstance instance = (*TLFL)[idx].instance;
emsMenu menuInfo;
Str63 title;
ControlHandle cntl;
Rect r;
SetRect(&r,-200,-200,50-200,13-200);
for(item=1;item<=(*TLFL)[idx].numMBoxContext;item++)
{
SetSize(menuInfo);
menuInfo.id = item;
menuInfo.desc = nil;
MightSwitch();
ems_mbox_context_info(instance,&menuInfo);
AfterSwitch();
PCopy(title,(*menuInfo.desc));
ZapHandle(menuInfo.desc);
cntl = NewControlSmall(winWP,&r,title,true,0,0,0,0,'plug'+item);
EmbedControl(cntl,(*tocH)->win->topMarginCntl);
ButtonFit(cntl);
}
}
}
/**********************************************************************
* ETLButtonHit - the user clicked a plug-in button
**********************************************************************/
void ETLButtonHit(MyWindowPtr win,short item)
{
WindowPtr winWP = GetMyWindowWindowPtr(win);
TOCHandle tocH = (TOCHandle)GetMyWindowPrivateData(win);
short idx;
if (tocH && PluginIDToIndex((*tocH)->pluginKey,&idx))
{
tlInstance instance = (*TLFL)[idx].instance;
emsMenu menuInfo;
FSSpec mailFolderSpec,spec;
AliasHandle mailbox=nil;
spec = GetMailboxSpec(tocH,-1);
FSMakeFSSpec(MailRoot.vRef, MailRoot.dirId, "", &mailFolderSpec);
NewAlias(&mailFolderSpec, &spec, &mailbox);
SetSize(menuInfo);
menuInfo.id = item;
menuInfo.desc = nil;
MightSwitch();
ems_mbox_context_hook(instance,mailbox,&menuInfo);
AfterSwitch();
ZapHandle(mailbox);
AuditHit(false, false, false, false, false, GetWindowKind(winWP), AUDITCONTROLID(GetWindowKind(winWP),ETL_CONTEXT_POPUP_MENU), mouseDown);
}
}
#if 0 // Not used anymore
/**********************************************************************
* ETLClickContextMenu - check for click in plug-in context menu
**********************************************************************/
Boolean ETLClickContextMenu(MyWindowPtr win,Point pt,Rect *rContentBox)
{
WindowPtr winWP = GetMyWindowWindowPtr(win);
Rect rIcon;
Boolean wasContextMenu = false;
TOCHandle tocH;
short idx;
Str255 s;
GetContextIconRect(rContentBox, &rIcon);
if (PtInRect(pt,&rIcon) &&
(tocH = (TOCHandle)GetMyWindowPrivateData(win)) &&
PluginIDToIndex((*tocH)->pluginKey,&idx))
{
// Click on context menu icon
tlInstance instance = (*TLFL)[idx].instance;
MenuHandle mh = NewMenu(ETL_CONTEXT_POPUP_MENU,"");
if (mh)
{
emsMenu menuInfo;
short item,sel;
InsertMenu(mh,-1);
MightSwitch();
for(item=1;item<=(*TLFL)[idx].numMBoxContext;item++)
{
SetSize(menuInfo);
menuInfo.id = item;
menuInfo.desc = nil;
ems_mbox_context_info(instance,&menuInfo);
MyAppendMenu(mh,PCopy(s,(*menuInfo.desc)));
}
AfterSwitch();
pt.v = rIcon.top; // Display menu at top/right of icon
pt.h = rIcon.right; // Display menu at top/right of icon
LocalToGlobal(&pt);
if (sel = AFPopUpMenuSelect(mh,pt.v,pt.h-2*MenuWidth(mh)/3,0))
{
FSSpec mailFolderSpec,spec;
AliasHandle mailbox=nil;
spec = GetMailboxSpec(tocH,-1);
FSMakeFSSpec(MailRoot.vRef, MailRoot.dirId, "", &mailFolderSpec);
NewAlias(&mailFolderSpec, &spec, &mailbox);
SetSize(menuInfo);
menuInfo.id = sel;
menuInfo.desc = nil;
MightSwitch();
ems_mbox_context_hook(instance,mailbox,&menuInfo);
AfterSwitch();
ZapHandle(mailbox);
}
DeleteMenu(GetMenuID(mh));
DisposeMenu(mh);
}
wasContextMenu = true;
AuditHit(false, false, false, false, false, GetWindowKind(winWP), AUDITCONTROLID(GetWindowKind(winWP),ETL_CONTEXT_POPUP_MENU), mouseDown);
}
return wasContextMenu;
}
#endif
/**********************************************************************
* ETLHasMBoxContextFolder - Does the plugin have ems_mbox_context_folder?
**********************************************************************/
Boolean ETLHasMBoxContextFolder(MyWindowPtr win)
{
TOCHandle tocH = (TOCHandle) GetMyWindowPrivateData(win);
short idx;
return ( tocH && (*tocH)->pluginKey && PluginIDToIndex((*tocH)->pluginKey, &idx) &&
ComponentFunctionImplemented((*TLFL)[idx].instance, kems_mbox_context_folderRtn) );
}
/**********************************************************************
* ETLMBoxContextFolder - Get the plugin folder, if any
**********************************************************************/
short ETLMBoxContextFolder(MyWindowPtr win, short * vRefNum, long * dirID)
{
short result = EMSR_UNKNOWN_FAIL;
TOCHandle tocH = (TOCHandle) GetMyWindowPrivateData(win);
short idx;
if ( tocH && (*tocH)->pluginKey && PluginIDToIndex((*tocH)->pluginKey, &idx) )
{
tlInstance instance = (*TLFL)[idx].instance;
if ( ComponentFunctionImplemented(instance, kems_mbox_context_folderRtn) )
{
emsMailBoxContextFolderData contextFolderData;
Zero(contextFolderData);
SetSize(contextFolderData);
contextFolderData.value = (*tocH)->pluginValue;
result = ems_mbox_context_folder(instance, &contextFolderData);
if (vRefNum)
*vRefNum = contextFolderData.pluginFolder.vRefNum;
if (dirID)
*dirID = SpecDirId(&contextFolderData.pluginFolder);
}
}
return result;
}
/**********************************************************************
* ETLGetPersonality - allow user to select a personality
**********************************************************************/
static pascal short ETLGetPersonality(emsGetPersonalityDataP pData)
{
short result = EMSR_OK;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
{
Str255 scratch;
PersHandle oldCur = CurPers;
long oldSize = pData->size;
Zero(pData->personality);
SetSize(pData->personality);
if (CurPers = pData->defaultPers ? PersList : PersChoose(pData->prompt))
{
// Return address info from personality
GetReturnAddr(scratch,false);
if (scratch[*scratch]=='>') --*scratch;
if (*scratch && scratch[1]=='<')
{
--*scratch;
BMD(scratch+2,scratch+1,*scratch);
}
pData->personality.address = NewString(scratch);
pData->personality.realname = NewString(GetPref(scratch,PREF_REALNAME));
pData->persCount = PersCount();
if (oldSize>(char*)&pData->personalityName-(char*)pData)
pData->personalityName = NewString(PCopy(scratch,(*CurPers)->name));
}
else
result = EMSR_USER_CANCELLED;
CurPers = oldCur;
}
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return result;
}
/**********************************************************************
* ETLGetPersonalityInfo - allow user to select a personality
**********************************************************************/
static pascal short ETLGetPersonalityInfo(emsGetPersonalityInfoDataP pData)
{
short result = EMSR_OK;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
{
Str255 scratch;
PersHandle oldCur = CurPers;
long oldSize = pData->size;
Zero(pData->personality);
SetSize(pData->personality);
PCopy(scratch,*pData->personalityName);
if (CurPers = FindPersByName(scratch))
{
// Return address info from personality
GetReturnAddr(scratch,false);
if (scratch[*scratch]=='>') --*scratch;
if (*scratch && scratch[1]=='<')
{
--*scratch;
BMD(scratch+2,scratch+1,*scratch);
}
pData->personality.address = NewString(scratch);
pData->personality.realname = NewString(GetPref(scratch,PREF_REALNAME));
}
else
result = EMSR_NO_ENTRY;
CurPers = oldCur;
}
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return result;
}
/**********************************************************************
* ETLRegenerate - regenerate plugin filters or nicknames
**********************************************************************/
static pascal void ETLRegenerate(emsRegenerateDataP pData)
{
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
switch (pData->which)
{
case emsRegenerateFilters:
DisposeFilters(&PreFilters);
DisposeFilters(&PostFilters);
GeneratePluginFilters();
break;
case emsRegenerateNicknames:
ZapPluginAliases();
ReadPluginNickFiles(true);
break;
}
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
}
/**********************************************************************
* ETLGetDirectory - return indicated folder spec
**********************************************************************/
static pascal short ETLGetDirectory(emsGetDirectoryDataP pData)
{
short result = EMSR_OK;
OSErr err = noErr;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
switch (pData->which)
{
case EMS_EudoraDir: err = FSMakeFSSpec(Root.vRef,Root.dirId,"",&pData->directory); break;
case EMS_AttachmentsDir: err = GetAttFolderSpec(&pData->directory); break;
case EMS_PluginFiltersDir: err = ETLGetPluginFolderSpec(&pData->directory,PLUGIN_FILTERS); break;
case EMS_PluginNicknamesDir: err = ETLGetPluginFolderSpec(&pData->directory,PLUGIN_NICKNAMES); break;
case EMS_ConfigDir: err = ETLGetPluginFolderSpec(&pData->directory,0); break;
case EMS_MailDir: err = FSMakeFSSpec(MailRoot.vRef,MailRoot.dirId,"",&pData->directory); break;
case EMS_NicknamesDir: err = SubFolderSpec(NICK_FOLDER,&pData->directory); break;
case EMS_SignaturesDir: err = SubFolderSpec(SIG_FOLDER,&pData->directory); break;
case EMS_SpoolDir: err = SubFolderSpec(SPOOL_FOLDER,&pData->directory); break;
case EMS_StationeryDir: err = SubFolderSpec(STATION_FOLDER,&pData->directory); break;
default: result = EMSR_INVALID; break;
}
if (err)
result = EMSR_UNKNOWN_FAIL;
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return result;
}
/**********************************************************************
* ETLUpdateWindows - handle Eudora window updates
**********************************************************************/
static pascal void ETLUpdateWindows(void)
{
UpdateAllWindows();
}
/**********************************************************************
* ETLCanTranslate - can any of the translators take a whack?
**********************************************************************/
OSErr ETLCanTranslate(TLMHandle translators,short context,emsMIMEHandle tlMIME,tlStringHandle *errorStr,long *errCode,emsHeaderDataP addrList,HeaderDHandle hdh)
{
short t;
short nT;
OSErr err;
FSSpec spec;
OSErr result = TLR_CANT_TRANS;
short group = REAL_BIG;
Boolean fGeneratedHeaders = false;
emsHeaderData list;
Zero(spec); // just to keep the compiler quiet
if (!TLSelList) return(TLR_CANT_TRANS);
ETLSortTranslators(translators);
nT = HandleCount(translators)-1;
if (hdh && !addrList)
{
// Generate header info from header desc
ETLBuildAddrList(nil,nil,hdh,&list,context);
addrList = &list;
fGeneratedHeaders = true;
}
for (t=0;t<nT;t++)
{
// call can_translate
err = CanTranslateFile(&(*TLFL)[(*translators)[t].module],context,(*translators)[t].id,tlMIME,
errorStr,errCode, nil, addrList, nil);
if (!err) err = TLR_NOW;
ZapHandle(errorStr);
// record error
(*translators)[t].result = err;
// if they're willing, I'm willing!
if (err==TLR_NOT_NOW || err==TLR_NOW)
{
result = err;
break;
}
}
if (fGeneratedHeaders)
ETLDisposeAddrList(addrList);
return(result);
}
/**********************************************************************
* ETLTranslate - actually call the translators
**********************************************************************/
OSErr ETLTranslate(TLMHandle translators,short context,emsMIMEHandle tlMIME,
FSSpecPtr source,emsMIMEHandle *tlMIMEOut,tlStringHandle *textOut,FSSpecPtr into,
tlStringHandle *errorStr,long *errCode,emsHeaderDataP addrList)
{
short n = HandleCount(translators)-1;
short nGood=0;
OSErr err;
emsMIMEHandle localTLMIME=nil;
long localErr;
#ifdef DEBUG
#ifdef DEBUGFILES
static short dbCount;
Str255 dbStr;
FInfo info;
FSSpec temp;
if (RunType==Debugging)
{
FSMakeFSSpec(Root.vRef,Root.dirId,ComposeString(dbStr,"\pETInput %d",++dbCount),&temp);
FSpDupFile(&temp,source,True,False);
FSpGetFInfo(&temp,&info);
info.fdType = 'TEXT';
info.fdCreator = 'MPS ';
FSpSetFInfo(&temp,&info);
}
#endif
#endif
if (!errCode) errCode = &localErr;
/*
* set up the translator vector
*/
while(n--)
{
if ((*translators)[n].result == TLR_NOW) break;
}
if ((*translators)[n].result != TLR_NOW) return(TLR_CANT_TRANS);
/*
* call the translator
*/
err = MyTranslateFile (&(*TLFL)[(*translators)[n].module], context, (*translators)[n].id, tlMIME,
source, &localTLMIME, into, nil, textOut, errorStr, errCode ,nil,
addrList, nil, (*translators)[n].nameHandle);
if (err==TLR_ABORTED) err = userCanceledErr;
if (err && err!=userCanceledErr && errorStr && *errorStr) ETLError((*TLFL)[(*translators)[n].module].moduleDescription,ETL_CANT_TRANSLATE,*errorStr,err,*errCode);
//ZapHandle(errorStr);
if (err==EMSR_DATA_UNCHANGED || err==TLR_NOT_NOW)
{
RecordTLID(source,ETLID(translators,n));
(*translators)[n].result = TLR_NOT_NOW;
}
/*
* record output
*/
if (!err && localTLMIME)
{
RecordTLMIME(into,localTLMIME);
if (tlMIMEOut)
{
*tlMIMEOut = localTLMIME;
localTLMIME = nil;
}
}
if (localTLMIME) ZapTLMIME(localTLMIME);
return(err);
}
/**********************************************************************v
* NewTLMIME - Allocate a tlMIME structure
**********************************************************************/
OSErr NewTLMIME(emsMIMEHandle *tlMIME)
{
if (*tlMIME = NewZH(struct emsMIMEtypeS))
(**tlMIME)->size = sizeof(struct emsMIMEtypeS);
return(MemError());
}
/**********************************************************************v
* NewMIME - Allocate a MIME structure and add some defaults
**********************************************************************/
static OSErr NewMIME(emsMIMEHandle *tlMIME,short mimeType,short subType)
{
OSErr err = NewTLMIME(tlMIME);
if (!err)
{
emsMIMEtypeP pMIME;
pMIME = LDRef(*tlMIME);
// Set up some defaults
if (mimeType)
GetRString(pMIME->mimeType,mimeType);
if (subType)
GetRString(pMIME->subType,subType);
GetRString(pMIME->mimeVersion,MIME_VERSION); // Default MIME version is 1.0
UL(*tlMIME);
}
return err;
}
/**********************************************************************
* DisposeTLMIME - dispose of an emsMIME structure
**********************************************************************/
void DisposeTLMIME(emsMIMEHandle tlMIME)
{
if (tlMIME)
{
if (*tlMIME)
{
DisposeTLMIMEParam((*tlMIME)->params);
DisposeTLMIMEParam((*tlMIME)->contentParams);
}
ZapHandle(tlMIME);
}
}
/**********************************************************************
* DisposeTLMIMEParam - dispose of an emsMIME parameter list
**********************************************************************/
void DisposeTLMIMEParam(emsMIMEParamHandle param)
{
if (param)
{
if (*param)
{
if ((*param)->next) DisposeTLMIMEParam((*param)->next);
ZapHandle((*param)->value);
}
ZapHandle(param);
}
}
/**********************************************************************
* DisposeTLMIME - dispose of an old tlMIME structure
**********************************************************************/
static void DisposeOldTLMIME(tlMIMEtypeP tlMIME)
{
if (tlMIME)
{
if (*tlMIME) DisposeOldTLMIMEParam((*tlMIME)->params);
ZapHandle(tlMIME);
}
}
/**********************************************************************
* DisposeTLMIMEParam - dispose of an old parameter list
**********************************************************************/
static void DisposeOldTLMIMEParam(tlMIMEParamP param)
{
if (param)
{
if (*param)
{
if ((*param)->next) DisposeOldTLMIMEParam((*param)->next);
// Don't dispose of (*param)->value since we didn't make a copy of it
}
ZapHandle(param);
}
}
/************************************************************************
* RecordTLID - record the id of this translator
************************************************************************/
OSErr RecordTLID(FSSpecPtr spec,uLong id)
{
short oldResF = CurResFile();
Handle idHandle = NuHandle(sizeof(long));
short refN;
OSErr err;
if (!idHandle) return(MemError());
**(long**)idHandle = id;
refN = FSpOpenResFile(spec,fsRdWrPerm);
if (refN==-1) err = ResError();
else
{
AddResource(idHandle,'etlI',1001,"");
if (err=ResError()) ZapHandle(idHandle);
else
{
idHandle = nil;
err = MyUpdateResFile(refN);
CloseResFile(refN);
}
}
ZapHandle(idHandle);
UseResFile (oldResF);
return(err);
}
/**********************************************************************
*
**********************************************************************/
OSErr AddTLMIME(emsMIMEHandle tlMIME,short what,PStr name, PStr value)
{
UHandle h2=nil;
emsMIMEParamHandle h3=nil;
OSErr err = noErr;
switch(what)
{
/*
* put in the type
*/
case TLMIME_TYPE:
PSCopy((*tlMIME)->mimeType,name);
break;
/*
* put in the subtype
*/
case TLMIME_SUBTYPE:
PSCopy((*tlMIME)->subType,name);
break;
/*
* add a parameter
*/
case TLMIME_CONTENTDISP_PARAM:
case TLMIME_PARAM:
// already in the list?
for (h3=(what==TLMIME_PARAM ? (*tlMIME)->params : (*tlMIME)->contentParams);h3;h3=(*h3)->next)
{
if (StringSame(LDRef(h3)->name,name))
{
// append
UL(h3);
PtrPlusHand(value+1,(*h3)->value,*value);
if (MemError()) return(MemError());
(*(*h3)->value)[0] += *value;
return(noErr);
}
UL(h3);
}
// not in the list. Make a new one.
h3 = NewZH(struct emsMIMEparamS);
h2 = NuHTempBetter(*value);
if (h2 && h3)
{
PSCopy((*h3)->name,name);
BMD(value+1,*h2,*value);
(*h3)->value = h2;
if (what==TLMIME_PARAM)
LL_Queue((*tlMIME)->params,h3,(emsMIMEParamHandle));
else
LL_Queue((*tlMIME)->contentParams,h3,(emsMIMEParamHandle));
h2 = nil;
h3 = nil;
}
else
err = MemError();
break;
/*
* put in the MIME version
*/
case TLMIME_VERSION:
PSCopy((*tlMIME)->mimeVersion,name);
break;
/*
* put in the content-disposition
*/
case TLMIME_CONTENTDISP:
PSCopy((*tlMIME)->contentDisp,name);
break;
}
ZapHandle(h2);
ZapHandle(h3);
return(err);
}
/**********************************************************************
* FlattenTLMIME - take an awful tlMIME thing and turn it into a single handle
**********************************************************************/
OSErr FlattenTLMIME(emsMIMEHandle tlMIME,FlatTLMIMEHandle *flat)
{
Accumulator a;
OSErr err;
emsMIMEParamHandle p;
emsMIMEtype localType;
emsMIMEparam localParam;
short len;
/*
* complete?
*/
if (!tlMIME || !(*tlMIME)->mimeType || !(*tlMIME)->subType) return(fnfErr);
localType = **tlMIME;
/*
* add basic stuff
*/
if (!(err=AccuInit(&a)))
if (!(err=AccuAddPtr(&a,localType.mimeType,*localType.mimeType+1)))
if (!(err=AccuAddPtr(&a,localType.subType,*localType.subType+1)))
{
/*
* add params
*/
for (p=(*tlMIME)->params;!err && p;p=(*p)->next)
{
localParam = **p;
if (!(err=AccuAddPtr(&a,localParam.name,*localParam.name+1)))
{
len = GetHandleSize((*p)->value);
if (!(err=AccuAddPtr(&a,(void*)&len,2)))
err = AccuAddHandle(&a,(*p)->value);
}
}
}
/*
* failure?
*/
if (err) AccuZap(a);
else
{
AccuTrim(&a);
*flat = a.data;
}
return(err);
}
/**********************************************************************
* UnflattenTLMIME - take a handle and turn it into an awful tlMIME thing
**********************************************************************/
OSErr UnflattenTLMIME(FlatTLMIMEHandle flat,emsMIMEHandle *tlMIME)
{
OSErr err = noErr;
Str63 name;
Str255 value;
long offset=0;
long len;
short paramLen;
if (err = NewTLMIME(tlMIME)) return(err);
len = GetHandleSize(flat);
/*
* type
*/
if (!err && offset<len)
{
PSCopy(name,(*flat)+offset);
offset += *name+1;
err = AddTLMIME(*tlMIME,TLMIME_TYPE,name,nil);
ASSERT(!err);
}
else err = fnfErr; //missing parts
/*
* subtype
*/
if (!err && offset<len)
{
PSCopy(name,(*flat)+offset);
offset += *name+1;
err = AddTLMIME(*tlMIME,TLMIME_SUBTYPE,name,nil);
ASSERT(!err);
}
else err = fnfErr;
/*
* params
*/
while (!err && offset<len)
{
PSCopy(name,(*flat)+offset);
offset += *name+1;
if (offset<len)
{
paramLen = (((uShort)(*flat)[offset])<<256)|(*flat)[offset+1];
MakePStr(value,*flat+offset+2,paramLen);
offset += paramLen+2;
err = AddTLMIME(*tlMIME,TLMIME_PARAM,name,value);
ASSERT(!err);
}
else err = fnfErr;
}
/*
* failure?
*/
if (err) ZapTLMIME(*tlMIME);
return(err);
}
/**********************************************************************
* ETLInterpretFile - interpret a MIME file, possibly using a translator
* source - source filespec
* resultRefN - result fileref; this is where the text display will go
* resultAcc - result accumulator; this is where text will go if resultRefN nil
**********************************************************************/
OSErr ETLInterpretFile(short context,FSSpecPtr source, short resultRefN, AccuPtr resultAcc, emsHeaderDataP addrList,Boolean *dontSave)
{
OSErr err;
emsMIMEHandle tlMIME=nil;
TLMHandle translators=nil;
FSSpec tempSpec;
UHandle textH=nil;
emsMIMEHandle newtlMIME = nil;
Handle errorStr=nil;
long returnCode;
Zero(tempSpec);
if (!(err=ETLGetTLMIME(source,&tlMIME)))
if (!(err=ETLListAllTranslators(&translators,context)))
{
ETLSortTranslators(translators);
err = ETLCanTranslate(translators,context,tlMIME,nil,nil,addrList,nil);
if (err==TLR_CANT_TRANS)
{
err = ETLCopyFile(source,resultRefN,True,nil);
}
else if (err==TLR_NOT_NOW && context==EMSF_ON_ARRIVAL)
{
RecordTL(source,translators);
}
else if (!err || err==TLR_NOW)
{
NewTempSpec(Root.vRef,Root.dirId,nil,&tempSpec);
FSpCreateResFile(&tempSpec,CREATOR,MIME_FTYPE,smSystemScript);
returnCode = 0;
err = ETLTranslate(translators,context,tlMIME,source,&newtlMIME,&textH,&tempSpec,&errorStr,&returnCode,addrList);
DisposeTLMIME(newtlMIME);
if (err == EMSR_DELETE_MESSAGE)
{
// the translator has asked that the message be deleted
if (!PrefIsSet(PREF_ETL_IGNORE_DELETES)) ETLDeleteRequest = true;
err = EMSR_OK; // continue processing
}
if (!err)
{
// See if should be marked clean
if (returnCode & EMSF_DONTSAVE)
{
*dontSave = true;
returnCode &= ~EMSF_DONTSAVE;
}
if (!textH || !(err=ETLOutputPtr(LDRef(textH)+1,**textH,resultRefN,resultAcc)))
{
Boolean fDoSig = false;
short sigListCount;
if (textH) ETLOutputPtr("\015",1,resultRefN,resultAcc);
ZapHandle(textH);
if (gpSignList && returnCode == TLC_SIGOK && gpSignList->count < kMaxSignList)
{
// Beginning of signature decoration
sigListCount = gpSignList->count++;
GetFPos(resultRefN, &gpSignList->begin[sigListCount]);
fDoSig = true;
}
err = ETLInterpretFile(context,&tempSpec,resultRefN,resultAcc,addrList,dontSave);
if (fDoSig)
{
// End of signature decoration
GetFPos(resultRefN, &gpSignList->end[sigListCount]);
}
// if new translator doesn't want it now, copy back to original
if (err==TLR_NOT_NOW && context==EMSF_ON_ARRIVAL)
FSpExchangeFiles(source,&tempSpec);
}
}
}
}
if (err==EMSR_ABORTED) err = userCanceledErr;
if (err && err!=userCanceledErr && err!=EMSR_DATA_UNCHANGED)
if (errorStr) AlertStr(BIG_OK_ALRT,Stop,LDRef(errorStr));
else if (context!=EMSF_ON_ARRIVAL) WarnUser(ETL_TRANS_FAILED,err);
if (err==userCanceledErr) ETLDeleteRequest = false; // leave the message alone if the user cancelled.
FSpDelete(&tempSpec);
ZapHandle(textH);
ZapHandle(errorStr);
ZapTLMIME(tlMIME);
ZapHandle(translators);
return(err);
}
/**********************************************************************
* ETLGetTLMIME - read the tlMIME thing back out of a file
**********************************************************************/
OSErr ETLGetTLMIME(FSSpecPtr spec,emsMIMEHandle *tlMIME)
{
Handle res;
short refN;
OSErr err = fnfErr;
short oldResF = CurResFile();
*tlMIME = nil;
if (-1!=(refN=FSpOpenResFile(spec,fsRdPerm)))
{
if (res=Get1Resource(MIME_FTYPE,1001))
err=UnflattenTLMIME(res,tlMIME);
CloseResFile(refN);
}
if (err==fnfErr) err = ETLReadTLMIME(spec,tlMIME);
UseResFile (oldResF);
return(err);
}
/**********************************************************************
* ETLReadTL - read the translator out of a file
**********************************************************************/
OSErr ETLReadTL(FSSpecPtr spec,long *id)
{
short refN;
OSErr err=fnfErr;
Handle res;
short oldResF = CurResFile();
refN = FSpOpenResFile(spec,fsRdPerm);
if (refN==-1) err = ResError();
else
{
if (res=GetResource('etlI',1001))
{
err = noErr;
*id = **(long**)res;
}
CloseResFile(refN);
}
UseResFile (oldResF);
return(err);
}
/**********************************************************************
* ETLReadTLMIME - read mime info
**********************************************************************/
OSErr ETLReadTLMIME(FSSpecPtr spec,emsMIMEHandle *tlMIME)
{
HeaderDHandle hdh = nil;
OSErr err = ETLCopyFile(spec,0,False,&hdh);
if (!err && hdh)
{
*tlMIME = (*hdh)->tlMIME;
(*hdh)->tlMIME = nil;
ZapHeaderDesc(hdh);
}
else if (!hdh)
{
err = NewMIME(tlMIME,MIME_TEXT,MIME_PLAIN);
}
return(err);
}
/**********************************************************************
* ETLCopyFile - copy a MIME file
**********************************************************************/
OSErr ETLCopyFile(FSSpecPtr spec,short refN,Boolean display,HeaderDHandle *theHeaders)
{
LineIOD lid;
LineIOP lip;
OSErr err;
UHandle buf = nil;
long size = GetRLong(BUFFER_SIZE);
/*
* set up stack, lineio, io buffer
*/
if (!TransContextStack && (err=StackInit(sizeof(LineIOP),&TransContextStack)))
return(WarnUser(ETL_TRANS_FAILED,err));
if (err=OpenLine(spec->vRefNum,spec->parID,spec->name,fsRdWrPerm,&lid))
return(FileSystemError(ETL_TRANS_FAILED,spec->name,err));
if (!(buf = NewIOBHandle(256,size))) err = MemError();
/*
* do the work
*/
lip = &lid;
if (buf && !(err=StackPush(&lip,TransContextStack)))
{
TransVector oldTrans = CurTrans;
CurTrans = TransTrans;
size = GetHandleSize(buf);
MoveHHi(buf);
err = ReadHeadAndBody(NULL,refN,LDRef(buf),size,display,theHeaders); //NULL is probably OK here. JDB 6/7/97
StackPop(nil,TransContextStack);
CurTrans = oldTrans;
}
/*
* cleanup
*/
CloseLine(&lid);
ZapHandle(buf);
if (err) WarnUser(ETL_TRANS_FAILED,err);
return(err);
}
/**********************************************************************
* ETLDisplayFile - display the contents of a file
**********************************************************************/
OSErr ETLDisplayFile(FSSpecPtr spec,PETEHandle pte)
{
FSSpec tempSpec;
OSErr err = noErr;
short refN;
MyWindowPtr win;
WindowPtr winWP;
long sel;
Str255 title;
long oldLen;
SignOffsetList signList;
Boolean dontSave = false;
UHandle textH;
TOCHandle tocH;
short sumNum;
AnyRich = AnyHTML = AnyFlow = AnyCharset = False;
if (err = NewTempSpec(Root.vRef,Root.dirId,nil,&tempSpec))
WarnUser(ETL_TRANS_FAILED,err);
else
{
FSpCreate(&tempSpec,CREATOR,'TEXT',smSystemScript);
if (err=FSpOpenDF(&tempSpec,fsRdWrPerm,&refN))
FileSystemError(ETL_TRANS_FAILED,tempSpec.name,err);
else
{
Handle hSignBounds = nil;
emsHeaderData addrList;
// Set up list to keep track of signature bars
gpSignList = &signList;
signList.count = 0;
// grab cache if we can
win = (*PeteExtra(pte))->win;
winWP = GetMyWindowWindowPtr(win);
textH = PeteText(pte);
sumNum = -1;
if (GetWindowKind(winWP) == MBOX_WIN)
{
tocH = (TOCHandle)GetMyWindowPrivateData(win);
if (pte==(*tocH)->previewPTE) sumNum = FirstMsgSelected(tocH);
}
else if (GetWindowKind(winWP) == MESS_WIN)
{
tocH = (*Win2MessH(win))->tocH;
sumNum = (*Win2MessH(win))->sumNum;
}
if (sumNum>=0)
{
CacheMessage(tocH,sumNum);
if ((*tocH)->sums[sumNum].cache)
HNoPurge((*tocH)->sums[sumNum].cache);
else
sumNum = -1;
}
// build the address list
ETLBuildAddrList(textH,nil,nil,&addrList,EMSF_Q4_TRANSMISSION);
if (sumNum!=-1) HPurge((*tocH)->sums[sumNum].cache);
err=ETLInterpretFile(TLF_ON_DISPLAY,spec,refN,nil,&addrList,&dontSave);
ETLDisposeAddrList(&addrList);
if (!err)
{
/*My - no need for flush */FSClose(refN); refN = 0;
if (pte)
{
PeteGetTextAndSelection(pte,nil,nil,&sel);
PETESelect(PETE,pte,sel,sel);
PeteSetURLRescan(pte,sel);
PetePlain(pte,kPETECurrentStyle,kPETECurrentStyle,peAllValid);
PETEInsertTextPtr(PETE,pte,-1,"\015\015",2,nil);
sel += 2; // Added 2 cr's
PETESelect(PETE,pte,sel,sel);
oldLen = PETEGetTextLen(PETE,pte);
err = InsertTextFile((*PeteExtra(pte))->win,&tempSpec,AnyRich||AnyHTML||AnyFlow||AnyCharset||AnyDelSP,AnyDelSP);
if (signList.count)
{
// Mark signatures
short sigIdx;
for (sigIdx=0;sigIdx<signList.count;sigIdx++)
{
long offsetBegin,offsetEnd,paraBegin,paraEnd,paraIdx;
PETEParaInfo pinfo;
offsetBegin = sel+signList.begin[sigIdx];
offsetEnd = sel+signList.end[sigIdx];
PeteEnsureBreak(pte,offsetBegin);
PeteEnsureBreak(pte,offsetEnd);
paraBegin = PeteParaAt(pte,offsetBegin);
paraEnd = PeteParaAt(pte,offsetEnd);
pinfo.tabHandle = nil;
PETEGetParaInfo(PETE,pte,kPETECurrentSelection,&pinfo); // Get the paragraph style here
pinfo.signedLevel++;
// Mark each paragraph
for (paraIdx = paraBegin;paraIdx <= paraEnd;paraIdx++)
PETESetParaInfo(PETE,pte,paraIdx,&pinfo,peSignedLevelValid);
}
// Restore original selection
PETESelect(PETE,pte,sel,sel);
}
}
else
{
GetRString(title,UNTITLED);
err = !(win=OpenText(&tempSpec,nil,nil,nil,True,title,False,False));
if (win) (*(TextDHandle)GetMyWindowPrivateData(win))->spec.vRefNum = 0;
}
WipeSpec(&tempSpec);
}
gpSignList = nil;
}
if (refN) /*My - no need for flush */FSClose(refN);
FSpDelete(&tempSpec);
}
if (dontSave && pte)
{
PeteCleanList(pte);
(*PeteExtra(pte))->win->isDirty = false;
}
return err;
}
/**********************************************************************
* ETLNameAndIcon - get translator name and icon
**********************************************************************/
void ETLNameAndIcon(short i,PStr name,Handle *suite)
{
*suite = (*TLFL)[i].moduleSuite;
PCopy(name,*(*TLFL)[i].moduleDescription);
}
/**********************************************************************
* TransRecvLine - receive a line for a translator
**********************************************************************/
OSErr TransRecvLine(TransStream stream, UPtr line,long *size)
{
#pragma unused (stream)
OSErr err;
LineIOP lip;
short result;
static Boolean wasNl=True;
err = StackTop(&lip,TransContextStack);
ASSERT(!err);
if (!err)
{
result = NLGetLine(line,*size,size,lip);
err = result<0;
if (!result)
{
*size = 2;
line[0]='.'; line[1]='\015'; line[2] = 0;
}
else if (wasNl && line[0]=='.')
{
BMD(line,line+1,*size);
++*size;
}
wasNl = line[*size]=='\015';
}
return(err);
}
/**********************************************************************
* ETLError - error with translator
**********************************************************************/
short ETLError(tlStringHandle description,short context,tlStringHandle errorStr,OSErr err,long subError)
{
Str255 string, error;
if (description) PSCopy(string,*description); else *string = 0;
if (errorStr) PSCopy(error,*errorStr); else *error = 0;
return(Aprintf(BIG_OK_ALRT,Caution,ETL_ERROR_FMT,string,context,error,err,subError));
}
/**********************************************************************
* ETLAddIcons - add translator icons to the composition window
**********************************************************************/
OSErr ETLAddIcons(MyWindowPtr win,short startNumber)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
ControlHandle theCtl;
short i;
Handle suite;
Rect r;
OSErr err = fnfErr;
long flags;
Zero(r);
if (TLQ4List)
{
for (i=HandleCount(TLQ4List);i--;)
{
flags = (*TLQ4List)[i].flags;
if (suite = (*TLQ4List)[i].suite)
{
if (theCtl = GetNewControlSmall(ICON_BAR_CNTL,winWP))
{
err = noErr; // found at least one
EmbedControl(theCtl,win->topMarginCntl);
SetBevelIcon(theCtl,0,0,0,suite);
SetControlReference(theCtl, 0xff000000 | startNumber+i);
(*Win2MessH(win))->nTransIcons++;
if (InTranslator((*Win2MessH(win))->hTranslators,ETLIconToID(i)))
SetControlValue(theCtl,1);
else if (SumOf(Win2MessH(win))->length==0 && flags & EMSF_DEFAULT_Q_ON)
{
// Default is on
// Turn on the translator
StringHandle properties = nil;
long selected;
selected = true;
QueuedProperties(i,&selected,&properties,true);
if (selected)
AddMessTranslator(Win2MessH(win),i,properties);
}
}
}
}
}
return(err);
}
/**********************************************************************
* ETLIconToID - turn an icon index into an id
**********************************************************************/
long ETLIconToID(short which)
{
if (TLQ4List && which<HandleCount(TLQ4List)) return(((*TLFL)[(*TLQ4List)[which].module].moduleID<<16L)|(*TLQ4List)[which].id);
else return(0);
}
/**********************************************************************
* ETLIconToDescriptions - grab the descriptions for a translator
**********************************************************************/
OSErr ETLIconToDescriptions(short which,PStr module,PStr translator)
{
if (TLQ4List && which<HandleCount(TLQ4List))
{
PCopy(module,*(*TLFL)[(*TLQ4List)[which].module].moduleDescription);
PCopy(translator,*(*TLQ4List)[which].nameHandle);
return(noErr);
}
else
{
*module = *translator = 0;
return(fnfErr);
}
}
/**********************************************************************
* ETLIDToIndex - turn an id into an index
**********************************************************************/
short ETLIDToIndex(long id)
{
short module = (id>>16)&0xffff;
short translator = id & 0xffff;
short index;
if (TLQ4List)
for (index = HandleCount(TLQ4List);index--;)
if ((*TLFL)[(*TLQ4List)[index].module].moduleID==module && (*TLQ4List)[index].id==translator)
return(index);
return(-1);
}
#define M_FTYPE MIME_FTYPE
/**********************************************************************
* ETLQueueMessage - if we have any ON_COMPLETION translators, translate how
**********************************************************************/
short ETLQueueMessage(MessHandle messH)
{
OSErr err = noErr;
TransInfoHandle translators = (*messH)->hTranslators;
Boolean doCompletion = false;
short i;
Str32 s;
// Got any ON_COMPLETION translators?
if (translators)
{
long flags = SumOf(messH)->flags;
for (i=HandleCount(translators);i--;)
{
short index;
index = ETLIDToIndex((*translators)[i].id);
if (index>=0 && (*TLQ4List)[index].flags & EMSF_Q4_COMPLETION)
{
doCompletion = true;
break;
}
}
}
if (doCompletion)
{
FSSpec raw, cooked;
OSErr transErr = 0;
// Do all EMSF_Q4_COMPLETION and EMSF_Q4_TRANSMISSION translators
if (!(err=NewTempSpec(Root.vRef,Root.dirId,nil,&raw)))
if (!(err=FSpCreate(&raw,CREATOR,M_FTYPE,smSystemScript)))
{
Uhandle text=nil;
HeadSpec hs;
// Create destination file in spool folder with same name as subject
if (!(err=MakeAttSubFolder(messH,SumOf(messH)->uidHash,&cooked)))
if (CompHeadFind(messH,SUBJ_HEAD,&hs) &&
!(CompHeadGetText(TheBody,&hs,&text)))
{
short saveLen;
short suffix = 2;
// Get Subject
MakePStr(cooked.name,*text,GetHandleSize(text));
ZapHandle(text);
// Make sure we have a unique file name
saveLen = *cooked.name;
while (!FSpExists(&cooked))
{
// No error means that the file/folder exists. Change the file name by adding a numeric suffix
NumToString(suffix++,s);
if (saveLen+*s > 30)
saveLen = 30-*s; // Name was too long
*cooked.name = saveLen; // Remove any suffix
PCatC(cooked.name,' ');
PCat(cooked.name,s);
}
if (!(err=FSpCreate(&cooked,CREATOR,M_FTYPE,smSystemScript)))
{
emsMIMEHandle tlMIME = nil;
short refN;
// Get raw message
if (!(err=FSpOpenDF(&raw,fsRdWrPerm,&refN)))
{
err = WriteMailFile(messH,refN,True,&tlMIME);
FSClose(refN);
}
// Do translation
if (!err) err = ETLTransOut(messH,tlMIME,&raw,&cooked);
transErr = err;
if (!err)
{
CompAttachSpec((*messH)->win,&cooked);
CompHeadFind(messH,0,&hs);
PeteDelete((*messH)->bodyPTE,hs.value,hs.stop);
ZapHandle(translators);
(*messH)->hTranslators = nil;
}
ZapTLMIME(tlMIME);
}
}
PrefIsSet(PREF_WIPE) ? WipeSpec(&raw):FSpDelete(&raw);
}
if (err && err!=userCanceledErr && !transErr) WarnUser(GENERAL,err);
}
return(err);
}
/**********************************************************************
* ETLSendMessage - send a message with the translators
**********************************************************************/
short ETLSendMessage(TransStream stream,MessHandle messH,Boolean chatter,Boolean sendDataCmd)
{
FSSpec raw, cooked;
OSErr err;
short refN;
long flags = SumOf(messH)->flags;
emsMIMEHandle tlMIME = nil;
OSErr transErr = 0;
if (!(err=NewTempSpec(Root.vRef,Root.dirId,nil,&raw)))
if (!(err=FSpCreate(&raw,CREATOR,M_FTYPE,smSystemScript)))
if (!(err=NewTempSpec(Root.vRef,Root.dirId,nil,&cooked)))
if (!(err=FSpCreate(&cooked,CREATOR,M_FTYPE,smSystemScript)))
{
{
if (!(err=FSpOpenDF(&raw,fsRdWrPerm,&refN)))
{
err = WriteMailFile(messH,refN,True,&tlMIME);
/*My - no need for flush */FSClose(refN);
}
if (!err) err = ETLTransOut(messH,tlMIME,&raw,&cooked);
transErr = err;
if (!err)
{
if (!(err=TransmitMessage(stream,messH,chatter,False,True,nil,sendDataCmd)))
if (!(err = SendRawMIME(stream,&cooked))) err = FinishSMTP(stream,messH);
}
}
PrefIsSet(PREF_WIPE) ? WipeSpec(&raw):FSpDelete(&raw);
if (*cooked.name) FSpDelete(&cooked);
}
if (err && err!=userCanceledErr && !transErr) WarnUser(GENERAL,err);
ZapTLMIME(tlMIME);
return(err);
}
/**********************************************************************
* ETLCanTransOut - can we translate this thing?
**********************************************************************/
OSErr ETLCanTransOut(MessHandle messH)
{
emsHeaderData list;
OSErr err = ETLBuildAddrList(PeteText(TheBody),(*messH)->extras.data,nil,&list,EMSF_Q4_TRANSMISSION);
TLMHandle transList=nil;
emsMIMEHandle tlmHandle=nil;
short i,n;
Handle errorStr=nil;
long errCode;
if (!err)
{
if (!(err=ETLListRequestedTranslators(&transList,(*messH)->hTranslators)))
{
short mimeType,subType;
if (MessFlagIsSet(messH,FLAG_HAS_ATT))
{
mimeType = MIME_MULTIPART;
subType = MIME_MIXED;
}
else
{
mimeType = MIME_TEXT;
subType = MIME_PLAIN;
}
if (!(err=NewMIME(&tlmHandle,mimeType,subType)))
{
n = HandleCount(transList);
for (i=0;i<n-1;i++)
{
err = CanTranslateFile(&(*TLFL)[(*transList)[i].module],EMSF_Q4_TRANSMISSION,(*transList)[i].id,
tlmHandle,&errorStr,&errCode,nil,&list,messH);
if (err==TLR_ABORTED) err = userCanceledErr;
if (err && err!=userCanceledErr && err!=TLR_NOW) ETLError((*TLFL)[(*transList)[i].module].moduleDescription,ETL_CANT_TRANSLATE,errorStr,err,errCode);
ZapHandle(errorStr);
if (!err) err = TLR_NOW;
if (err!=TLR_NOW) break;
}
}
}
}
ZapHandle(transList);
ETLDisposeAddrList(&list);
ZapTLMIME(tlmHandle);
return(err);
}
/**********************************************************************
* ETLTransOut - actually translate something
**********************************************************************/
OSErr ETLTransOut(MessHandle messH,emsMIMEHandle tlMIME,FSSpecPtr from,FSSpecPtr to)
{
emsHeaderData addrList;
OSErr err;
TLMHandle transList=nil;
err = ETLBuildAddrList(PeteText(TheBody),(*messH)->extras.data,nil,&addrList,EMSF_Q4_TRANSMISSION);
if (!err)
{
if (!(err=ETLListRequestedTranslators(&transList,(*messH)->hTranslators)))
err = ETLTransOutLow(transList,&addrList,tlMIME,from,to,messH);
}
ZapHandle(transList);
ETLDisposeAddrList(&addrList);
return(err);
}
/**********************************************************************
* ETLTransOutLow - perform first translation in the list, and recurse
**********************************************************************/
static OSErr ETLTransOutLow(TLMHandle transList,emsHeaderDataP addrList,
emsMIMEHandle tlMIME,FSSpecPtr from,FSSpecPtr into,MessHandle messH)
{
OSErr err;
short n,i;
FSSpec temp;
emsMIMEHandle tlMIMEOut=nil;
tlStringHandle errorStr=nil;
long localErr;
StringHandle properties;
#ifdef DEBUG
#ifdef DEBUGFILES
static short dbCount;
Str255 dbStr;
FInfo info;
if (RunType==Debugging)
{
FSMakeFSSpec(Root.vRef,ComposeString(dbStr,"\pEOInput %d",++dbCount),&temp);
FSpDupFile(&temp,from,True,False);
FSpGetFInfo(&temp,&info);
info.fdType = 'TEXT';
info.fdCreator = 'MPS ';
FSpSetFInfo(&temp,&info);
}
#endif
#endif
Zero(temp);
// Look for queued properties
properties = GetQueuedProperties(messH,((*TLFL)[(*transList)[0].module].moduleID<<16L)|(*transList)[0].id);
err = CanTranslateFile(&(*TLFL)[(*transList)[0].module],EMSF_Q4_TRANSMISSION,(*transList)[0].id,
tlMIME,&errorStr,&localErr,properties,addrList,messH);
if (err==TLR_ABORTED) err = userCanceledErr;
if (!err) err = TLR_NOW;
if (err!=TLR_NOW && err!=userCanceledErr)
{
ETLError((*TLFL)[(*transList)[0].module].moduleDescription,ETL_CANT_TRANSLATE,errorStr,err,localErr);
}
else
{
ZapHandle(errorStr);
err = MyTranslateFile (&(*TLFL)[(*transList)[0].module], EMSF_Q4_TRANSMISSION, (*transList)[0].id, tlMIME,
from, &tlMIMEOut,into, nil, nil, &errorStr, &localErr, properties,
addrList, messH, (*transList)[0].nameHandle);
if (err==TLR_ABORTED) err = userCanceledErr;
if (err && err!=EMSR_DATA_UNCHANGED)
{
if (err!=userCanceledErr) ETLError((*TLFL)[(*transList)[0].module].moduleDescription,ETL_CANT_TRANSLATE,errorStr,err,localErr);
WipeSpec(into);
}
else
{
ZapHandle(errorStr);
if (err==EMSR_DATA_UNCHANGED)
{
// Data unchanged, so put from file into into file and we're done
if (err=FSpExchangeFiles(from,into))
FileSystemError(ETL_CANT_TRANSLATE,from->name,err);
else
err = 0;
}
else
RecordTLMIME(into,tlMIMEOut);
if (!err)
{
n = HandleCount(transList);
if (n>2)
{
for (i=0;i<n-1;i++) (*transList)[i] = (*transList)[i+1];
SetHandleSize((Handle)transList,(n-1)*sizeof(**transList));
NewTempSpec(into->vRefNum,into->parID,nil,&temp);
FSpCreate(&temp,CREATOR,MIME_FTYPE,smSystemScript);
if (err=ResError()) FileSystemError(ETL_CANT_TRANSLATE,temp.name,err);
else if (err=FSpExchangeFiles(&temp,into))
{
WipeSpec(&temp);
FileSystemError(ETL_CANT_TRANSLATE,temp.name,err);
}
else
{
err = ETLTransOutLow(transList,addrList,tlMIMEOut,&temp,into,messH);
WipeSpec(&temp);
}
}
}
}
}
ZapHandle(errorStr);
ZapTLMIME(tlMIMEOut);
return(err);
}
/**********************************************************************
* MakeAddress - return a emsAddressH for the indicated address
**********************************************************************/
static emsAddressH MakeAddress(StringPtr sAddress,StringPtr sName)
{
emsAddressH hAddress = nil;
if ((*sAddress || *sName) && (hAddress=NuHandleClear(sizeof(emsAddress))))
{
emsAddressP pAddress;
pAddress = LDRef(hAddress);
pAddress->size = sizeof(emsAddress);
if (*sAddress)
pAddress->address = NewString(sAddress);
if (*sName)
pAddress->realname = NewString(sName);
UL(hAddress);
}
return hAddress;
}
/**********************************************************************
* GetAddressesFromHandle - get addresses from a handle
**********************************************************************/
static emsAddressH GetAddressesFromHandle(Uhandle text,Boolean expandNicks)
{
UHandle addr;
UHandle rawAddresses;
short err=0;
Str255 s;
Str255 raw;
emsAddressH hAddress = nil;
emsAddressH hLastAddress = nil;
emsAddressH hFirstAddress = nil;
err=SuckAddresses(&rawAddresses,text,True,false,False,nil);
ZapHandle(text);
if (rawAddresses && **rawAddresses)
{
long offset;
if (expandNicks)
{
ExpandAliases(&addr,rawAddresses,0,True);
ZapHandle(rawAddresses);
}
else
addr = rawAddresses;
for (offset=0;!err && (*addr)[offset];offset+=(*addr)[offset]+2)
{
MakePStr(raw,(*addr)+offset+1,(*addr)[offset]);
ShortAddr(s,raw);
//Folder Carbon Copy no FCC's in Light. Flag them as wrong
if (HasFeature (featureFcc))
if (IsFCCAddr(s)) continue; // skip fcc's
BeautifyFrom(raw);
if (StringSame(raw,s))
*raw = 0; // No real name
if (hAddress = MakeAddress(s,raw))
{
if (hLastAddress)
(*hLastAddress)->next = hAddress;
hLastAddress = hAddress;
if (!hFirstAddress)
hFirstAddress = hAddress;
}
}
ZapHandle(addr);
}
return hFirstAddress;
}
/**********************************************************************
* GetAddressesFromHeader - get addresses from a header
**********************************************************************/
static emsAddressH GetAddressesFromHeader(UHandle textIn,short header,Boolean expandNicks)
{
short err=0;
Uhandle text=nil;
emsAddressH hFirstAddress = nil;
HeadSpec hs;
Str63 hName;
if (HandleHeadFindStr(textIn,header?GetRString(hName,HeaderStrn+header):"",&hs) &&
!(err=HandleHeadGetText(textIn,&hs,&text)))
{
hFirstAddress = GetAddressesFromHandle(text,expandNicks);
}
return hFirstAddress;
}
/**********************************************************************
* - get addresses from a header
**********************************************************************/
static emsAddressH FindAddress(Accumulator acc, short index,Boolean expandNicks)
{
short err=0;
Uhandle text=nil;
emsAddressH hAddress = nil;
emsAddressH hLastAddress = nil;
emsAddressH hFirstAddress = nil;
Str32 name;
UPtr pHeader;
long length;
GetRString(name,HeaderStrn+index);
length = acc.offset;
if (pHeader = FindHeaderString(*acc.data,name,&length,false))
{
PtrToHand(pHeader, &text, length);
hFirstAddress = GetAddressesFromHandle(text,expandNicks);
}
return hFirstAddress;
}
/**********************************************************************
* ETLBuildAddrList - build an address list
**********************************************************************/
OSErr ETLBuildAddrList(UHandle textIn,UHandle moreHeaders,HeaderDHandle hdh,emsHeaderDataP addrList,short context)
{
Str255 sName;
HeadSpec hs;
Uhandle text=nil;
Accumulator acc;
WriteZero(addrList,sizeof(emsHeaderData));
addrList->size = sizeof(emsHeaderData);
if (textIn || hdh)
{
if (gTranslatorFlags & (EMSF_BASIC_HEADERS+EMSF_ALL_HEADERS))
{
// Do BASIC headers
Boolean expandNicks = ContextRequiresExpansion(context);
if (textIn)
{
// Get from message header
// Get From, To, CC, BCC headers
addrList->from = GetAddressesFromHeader(textIn,FROM_HEAD,expandNicks);
addrList->to = GetAddressesFromHeader(textIn,TO_HEAD,expandNicks);
addrList->cc = GetAddressesFromHeader(textIn,CC_HEAD,expandNicks);
addrList->bcc = GetAddressesFromHeader(textIn,BCC_HEAD,expandNicks);
// Get Subject
if (HandleHeadFindStr(textIn,GetRString(sName,HeaderStrn+SUBJ_HEAD),&hs) &&
!(HandleHeadGetText(textIn,&hs,&text)))
{
MakePStr(sName,*text,GetHandleSize(text));
addrList->subject = NewString(sName);
ZapHandle(text);
}
}
else
{
long length;
UPtr pHeader;
acc = (*hdh)->fullHeaders;
HLock(acc.data);
// Get From, To, CC, BCC headers
addrList->from = FindAddress(acc,FROM_HEAD,expandNicks);
addrList->to = FindAddress(acc,TO_HEAD,expandNicks);
addrList->cc = FindAddress(acc,CC_HEAD,expandNicks);
addrList->bcc = FindAddress(acc,BCC_HEAD,expandNicks);
// Get Subject
GetRString(sName,HeaderStrn+SUBJ_HEAD);
length = acc.offset;
if (pHeader = FindHeaderString(*acc.data,sName,&length,false))
{
MakePStr(sName,pHeader,length);
addrList->subject = NewString(sName);
}
HUnlock(acc.data);
}
}
if ((gTranslatorFlags & EMSF_ALL_HEADERS) && (context==EMSF_ON_ARRIVAL || context==EMSF_ON_DISPLAY || context==EMSF_Q4_TRANSMISSION || context==EMSF_ON_REQUEST))
{
// Get raw 822 headers
if (textIn)
{
if (HandleHeadFindStr(textIn,"",&hs))
{
hs.stop = hs.start-1;
hs.start = 0;
hs.value = 0;
if (!(HandleHeadGetText(textIn,&hs,&text)))
{
addrList->rawHeaders = text;
if (moreHeaders) HandPlusHand(moreHeaders,text);
}
}
}
else
{
acc = (*hdh)->fullHeaders;
HLock(acc.data);
PtrToHand(*acc.data, &addrList->rawHeaders, acc.offset);
HUnlock(acc.data);
}
}
}
return(noErr);
}
/**********************************************************************
* ETLBuildOldAddrList - build a translation address list for version 1
**********************************************************************/
OSErr ETLBuildOldAddrList(MessHandle messH,tlAddrListHandle *addrList,Boolean expandNicks)
{
Accumulator a;
OSErr err = AccuInit(&a);
BinAddrHandle addr = NuHandle(0);
Str255 s;
Str255 raw;
long offset;
long theNil = 0;
if (!err && !(err=MemError()))
{
MessReturnAddr(messH,s);
if (!(err=AccuAddHandleToPtr(&a,s,*s+1)))
{
GetRealname(s);
if (*s)
err=AccuAddHandleToPtr(&a,s,*s+1);
else
err=AccuAddPtr(&a,(void*)&theNil,sizeof(addr));
if (!err)
if (!(err=AccuAddPtr(&a,(void*)&theNil,sizeof(addr))))
{
if (!(err = GatherCompAddresses((*messH)->win,addr)))
{
if (expandNicks)
{
BinAddrHandle exp;
if (!(err=ExpandAliases(&exp,addr,0,true)))
{
ZapHandle(addr);
addr = exp;
}
}
for (offset=0;!err && (*addr)[offset];offset+=(*addr)[offset]+2)
{
MakePStr(raw,(*addr)+offset+1,(*addr)[offset]);
ShortAddr(s,raw);
//Folder Carbon Copy no FCC's in Light. Flag them as wrong
if (HasFeature (featureFcc))
if (IsFCCAddr(s)) continue; // skip fcc's
if (!(err=AccuAddHandleToPtr(&a,s,*s+1)))
{
BeautifyFrom(raw);
if (!(err=AccuAddHandleToPtr(&a,raw,*raw+1)))
err=AccuAddPtr(&a,(void*)&theNil,sizeof(addr));
}
}
}
}
}
}
if (!err) err = AccuAddPtr(&a,(void*)&theNil,sizeof(addr));
if (!err)
{
AccuTrim(&a);
*addrList = (void*)a.data;
a.data = nil;
}
ZapHandle(addr);
AccuZap(a);
return(err);
}
/**********************************************************************
* ZapAddress - dispose of an address list
**********************************************************************/
static void ZapAddress(emsAddressH addr)
{
emsAddressH next;
while (addr)
{
StringHandle address, name;
if (address = (*addr)->address) DisposeHandle(address);
if (name = (*addr)->realname) DisposeHandle(name);
next = (*addr)->next;
DisposeHandle((Handle)addr);
addr = next;
}
}
/**********************************************************************
* DisposeAddrList - destroy a translation address list thing
**********************************************************************/
void ETLDisposeAddrList(emsHeaderDataP addrList)
{
if (addrList)
{
ZapAddress(addrList->to);
ZapAddress(addrList->from);
ZapAddress(addrList->cc);
ZapAddress(addrList->bcc);
ZapHandle(addrList->subject);
ZapHandle(addrList->rawHeaders);
}
}
/**********************************************************************
* DisposeOldAddrList - destroy a version 1 translation address list thing
**********************************************************************/
static void DisposeOldAddrList(tlAddrListHandle addrList)
{
short i;
if (addrList)
{
for (i=HandleCount(addrList);i--;) ZapHandle((*addrList)[i]);
ZapHandle(addrList);
}
}
/**********************************************************************
* ETLTransSelection - translate the selection in a window
**********************************************************************/
OSErr ETLTransSelection(PETEHandle pte,HSPtr hs,short item)
{
short n = HandleCount(TLSelList);
TLMaster tlm;
UHandle text=nil;
OSErr err = noErr;
long len;
while (n-- && (*TLSelList)[n].menuItem!=item);
if (n<0) return(WarnUser(ETL_CANT_FIND_TRANS,item));
tlm = (*TLSelList)[n];
if (tlm.flags & TLF_REQUIRES_MIME) return(WarnUser(ETL_IM_STUPID,0));
if (tlm.flags & EMSF_ALL_TEXT)
{
// Use all text
hs->start = hs->value = 0;
hs->stop = PETEGetTextLen(PETE,pte);
}
if ((CurrentModifiers()&optionKey) && PeteParaAt(pte,hs->start)!=PeteParaAt(pte,hs->stop) && UseFlowIn)
{
LightQuote(pte,hs->start,hs->stop,&hs->start,&hs->stop);
hs->value = hs->start;
PeteSelect(nil,pte,hs->start,hs->stop);
PeteWrap(nil,pte,true);
PeteGetTextAndSelection(pte,nil,&hs->start,&hs->stop);
hs->value = hs->start;
}
if (!(err=CompHeadGetText(pte,hs,&text)))
{
#ifdef NEVER
if () err = ETLTransHandleBuf(&text,&tlm);
else
#endif
err = ETLTransHandleFile(&text,&tlm,pte);
len = GetHandleSize(text);
if (!err)
{
PetePrepareUndo(pte,peUndoPaste,hs->value,hs->stop,nil,nil);
if (!(err = PeteDelete(pte,hs->value,hs->stop)))
if (!(err = PETEInsertText(PETE,pte,hs->value,text,nil)))
{
text = nil;
PeteSelect((*PeteExtra(pte))->win,pte,hs->value,hs->value+len);
}
PeteFinishUndo(pte,peUndoPaste,hs->value,hs->value+len);
PeteChanged(pte,hs->value,hs->value+len);
}
}
ZapHandle(text);
return(err);
}
#ifdef NEVER
/**********************************************************************
* ETLTransHandleBuf - translate a handle, using the buffer calls
**********************************************************************/
OSErr ETLTransHandleBuf(UHandle *text,TLMPtr tlm)
{
return(WarnUser(ETL_IM_STUPID,1));
}
#endif
/**********************************************************************
* ETLTransHandleFile - translate a handle, using files as intermediaries
**********************************************************************/
static OSErr ETLTransHandleFile(UHandle *text,TLMPtr tlm,PETEHandle pte)
{
FSSpec raw, translated;
OSErr err;
UHandle errorStr = nil;
emsMIMEHandle tlMIME = nil;
Handle headers=nil;
long localErr;
long len;
long bo;
emsMIMEHandle localTLMIME=nil;
emsHeaderData addrList;
#ifdef DEBUG
#ifdef DEBUGFILES
static short dbCount;
Str255 dbStr;
FInfo info;
FSSpec temp;
#endif
#endif
Zero(raw);
Zero(translated);
PlainTextMIMEStuff(&tlMIME,(tlm->flags&TLF_REQUIRES_MIME) ? &headers : nil);
NewTempSpec(Root.vRef,Root.dirId,nil,&raw);
NewTempSpec(Root.vRef,Root.dirId,nil,&translated);
if ((tlm->flags&TLF_REQUIRES_MIME) && (err=AddLf(*text)) ||
(err=FSpCreate(&raw,CREATOR,'TEXT',smSystemScript)) ||
(err=FSpCreate(&translated,CREATOR,'TEXT',smSystemScript)) ||
(headers && (err=Blat(&raw,headers,False))) ||
(err=Blat(&raw,*text,True)))
FileSystemError(ETL_CANT_TRANSLATE,raw.name,err);
else
{
#ifdef DEBUG
#ifdef DEBUGFILES
if (RunType==Debugging)
{
FSMakeFSSpec(Root.vRef,ComposeString(dbStr,"\pESInput %d",++dbCount),&temp);
FSpDupFile(&temp,&raw,True,False);
FSpGetFInfo(&temp,&info);
info.fdType = 'TEXT';
info.fdCreator = 'MPS ';
FSpSetFInfo(&temp,&info);
}
#endif
#endif
ZapHandle(*text);
Zero(addrList);
if (tlm->flags & (EMSF_BASIC_HEADERS+EMSF_ALL_HEADERS))
ETLBuildAddrList(PeteText(pte),nil,nil,&addrList,EMSF_ON_REQUEST);
err = CanTranslateFile(&(*TLFL)[tlm->module],TLF_ON_REQUEST,tlm->id,
tlMIME,&errorStr,&localErr,nil,&addrList,nil);
if (err==TLR_ABORTED) err = userCanceledErr;
if (!err || err==TLR_NOW)
{
err = MyTranslateFile(&(*TLFL)[tlm->module],TLF_ON_REQUEST,tlm->id,tlMIME,&raw,&localTLMIME,
&translated,nil,nil,&errorStr, &localErr,nil,
&addrList,nil, tlm->nameHandle);
if (err==TLR_ABORTED) err = userCanceledErr;
}
ETLDisposeAddrList(&addrList);
if (err)
{
if (err!=userCanceledErr && err!=EMSR_DATA_UNCHANGED) ETLError((*TLFL)[tlm->module].moduleDescription,ETL_CANT_TRANSLATE,errorStr,err,localErr);
ZapHandle(errorStr);
}
else
{
if (err=Snarf(&translated,text,0))
FileSystemError(ETL_CANT_TRANSLATE,translated.name,err);
#ifdef DEBUG
#ifdef DEBUGFILES
if (RunType==Debugging)
{
FSMakeFSSpec(Root.vRef,ComposeString(dbStr,"\pESOutput %d",dbCount),&temp);
FSpDupFile(&temp,&translated,True,False);
FSpGetFInfo(&temp,&info);
info.fdType = 'TEXT';
info.fdCreator = 'MPS ';
FSpSetFInfo(&temp,&info);
}
#endif
#endif
if (tlm->flags&TLF_GENERATES_MIME)
{
len = RemoveChar('\012',LDRef(*text),GetHandleSize_(*text));
UL(text);
SetHandleBig(*text,len);
bo = BodyOffset(*text);
BMD(**text+len,**text,len-bo);
SetHandleBig(*text,len-bo);
}
}
}
if (err) ZapHandle(*text);
ZapTLMIME(tlMIME);
ZapTLMIME(localTLMIME);
WipeSpec(&raw);
WipeSpec(&translated);
ZapHandle(errorStr);
ZapHandle(headers);
return(err);
}
/**********************************************************************
* PlainTextMIMEStuff - generate plaintext headers
**********************************************************************/
OSErr PlainTextMIMEStuff(emsMIMEHandle *tlMIME,Handle *headers)
{
emsMIMEHandle localTLMIME=nil;
Str255 scratch;
Str63 scratch2;
OSErr err;
if (tlMIME) *tlMIME = nil;
if (headers) *headers = nil;
if (!(err=NewMIME(&localTLMIME,headers?MIME_TEXT:MIME_APPLICATION,headers?MIME_PLAIN:MIME_MACTEXT)))
if (!(err=AddTLMIME(localTLMIME,TLMIME_PARAM,
GetRString(scratch,MIME_CHARSET),GetRString(scratch2,MIME_MAC))))
if (headers)
{
ComposeString(scratch,"\p%r: %r/%r; %r=%r\015\012\015\012",InterestHeadStrn+hContentType,
headers?MIME_TEXT:MIME_APPLICATION,
headers?MIME_PLAIN:MIME_MACTEXT,
MIME_CHARSET,MIME_MAC);
if (*headers=NuHTempBetter(*scratch))
BMD(scratch+1,**headers,*scratch);
else err = MemError();
}
if (err) ZapTLMIME(localTLMIME);
else if (tlMIME) *tlMIME = localTLMIME;
return(err);
}
/**********************************************************************
* ETLID - get the id value for a translator
**********************************************************************/
long ETLID(TLMHandle tl,short index)
{
short module;
short id;
id = (*tl)[index].id;
module = (*TLFL)[(*tl)[index].module].moduleID;
return((module<<16L)|id);
}
/**********************************************************************
* GetTransIcon - get a translator icon suite
**********************************************************************/
static OSErr GetTransIcon(TLFLPtr tlfl,long id,Handle *suite)
{
OSErr err = fnfErr;
*suite = nil;
if (UseParameterBlockStyleFunctions(tlfl->version))
{
emsTranslator transInfo;
Zero(transInfo);
SetSize(transInfo);
transInfo.id = id;
MightSwitch();
err = ems_translator_info(tlfl->instance,&transInfo);
AfterSwitch();
ZapHandle(transInfo.desc);
*suite = transInfo.icon;
}
else
{
MightSwitch();
err = tl_translator_info(tlfl->instance,id,nil,nil,nil,nil,suite);
AfterSwitch();
}
return(err);
}
/**********************************************************************
* ETLIDToFileIcon - turn a translator id into an icon suite
**********************************************************************/
OSErr ETLIDToFileIcon(long id,Handle *suite)
{
short mId = id>>16;
short tId = id&0xffff;
short i;
OSErr err = fnfErr;
if (TLFL)
{
for (i=HandleCount(TLFL);i--;)
if ((*TLFL)[i].moduleID==mId)
{
err = GetTransIcon(&(*TLFL)[i],tId,suite);
break;
}
}
return(err);
}
/**********************************************************************
* IsSystemComponent - is this a component in the System folder?
**********************************************************************/
static Boolean IsSystemComponent(Component comp)
{
short i;
if (ghSystemComponents)
{
for (i=HandleCount(ghSystemComponents);i--;)
if (comp == (*ghSystemComponents)[i])
return true;
}
return false;
}
/**********************************************************************
*
**********************************************************************/
void ETLCleanup(void)
{
short i;
// clean up importer plugin icons
if (TLImporterList)
for (i=HandleCount(TLImporterList);i--;)
DisposeIconSuite((*TLImporterList)[i].suite, true);
if (TLFL)
for (i=HandleCount(TLFL);i--;)
{
tlInstance instance = (*TLFL)[i].instance;
ComponentDescription info;
Component comp=nil;
Boolean fUnregister;
if (UseParameterBlockStyleFunctions((*TLFL)[i].version))
{
if (ComponentFunctionImplemented(instance,kems_plugin_finishRtn))
{
MightSwitch();
ems_plugin_finish(instance);
AfterSwitch();
}
}
else
{
if (ComponentFunctionImplemented(instance,ktl_module_finishRtn))
{
MightSwitch();
tl_module_finish(instance);
AfterSwitch();
}
}
// Unregister only if it is not a system component
fUnregister = !HaveTheDiseaseCalledOSX() && !(!GetComponentInfo((Component)instance,&info,nil,nil,nil) &&
(comp = FindNextComponent(comp, &info)) &&
IsSystemComponent(comp));
CloseComponent(instance);
if (fUnregister)
UnregisterComponent(comp);
}
}
/**********************************************************************
* ETLIdle - called from main event loop. Call plug-ins that want idle time
**********************************************************************/
void ETLIdle(long flags)
{
long thisTime;
short i;
emsIdleData idleData;
if (gIdleTimeCount && TLFL)
{
TLFLPtr pTLFL;
// Search for and call any plug-ins whose time has come
thisTime = (TickCount()*50)/3; // (ticks / 60 * 1000) Roughly in milliseconds
pTLFL = LDRef(TLFL);
for (i=HandleCount(TLFL);i--;pTLFL++)
{
if (pTLFL->idleTimeFreq && ((thisTime - pTLFL->lastIdleTime >= pTLFL->idleTimeFreq) || flags==EMSFIDLE_PRE_SEND))
{
// Call this one
idleData.flags = flags;
idleData.idleTimeFreq = &pTLFL->idleTimeFreq;
idleData.progress = TO_UPP_OR_NOT_TO_UPP(ETLProgress3);
MightSwitch();
ems_idle(pTLFL->instance,&idleData);
AfterSwitch();
pTLFL->lastIdleTime = thisTime;
}
}
UL(TLFL);
}
}
/**********************************************************************
* ETLEudoraModeNotification - called after loading plugins and after registration mode change.
**********************************************************************/
void ETLEudoraModeNotification(ModeEventEnum modeEvent, ModeTypeEnum newMode )
{
short i;
emsEudoraModeNotificationData modeNotificationData;
if (TLFL)
{
TLFLPtr pTLFL;
pTLFL = LDRef(TLFL);
for (i=HandleCount(TLFL);i--;pTLFL++)
{
if (ComponentFunctionImplemented(pTLFL->instance,kems_eudora_mode_notificationRtn))
{
// Call this one
modeNotificationData.size = sizeof(emsEudoraModeNotificationData);
modeNotificationData.modeEvent = EMS_ModeChanged;
modeNotificationData.isFullFeatureSet = newMode;
modeNotificationData.needsFullFeatureSet = EMS_ModeFree;
modeNotificationData.downgradeWasBeingUsed = false;
MightSwitch();
ems_eudora_mode_notification(pTLFL->instance,&modeNotificationData);
AfterSwitch();
pTLFL->modeNeeded = modeNotificationData.needsFullFeatureSet;
pTLFL->downgradeWasBeingUsed = modeNotificationData.downgradeWasBeingUsed;
}
}
UL(TLFL);
}
}
/**********************************************************************
* CanTranslateFile - determine if translator can act on this file
**********************************************************************/
static OSErr CanTranslateFile(TLFLPtr pTLFL,long context,short trans_id,
emsMIMEHandle in_mime, StringPtr **out_error,
long *out_code, StringHandle queuedProperties, emsHeaderDataP header, MessHandle messH)
{
long out_len; /* Place to return estimated length (unused) */
OSErr err;
tlInstance instance = pTLFL->instance;
Boolean pb = UseParameterBlockStyleFunctions(pTLFL->version);
if (pb)
{
emsTranslator trans; /* In: Translator Info */
emsDataFile inTransData; /* In: What to translate */
emsResultStatus transStatus; /* Out: Translations Status information */
Zero(trans);
SetSize(trans);
trans.id = trans_id;
trans.properties = queuedProperties;
Zero(inTransData);
SetSize(inTransData);
inTransData.context = context;
inTransData.mimeInfo = in_mime;
inTransData.header = header;
// inTransData.file (file parameter not used for can_translate)
Zero(transStatus);
SetSize(transStatus);
MightSwitch();
err = ems_can_translate(instance,&trans,&inTransData,&transStatus);
AfterSwitch();
if (transStatus.desc)
ZapHandle(transStatus.desc);
if (out_error)
*out_error = transStatus.error;
else
ZapHandle(transStatus.error);
if (out_code)
*out_code = transStatus.code;
HUnlock((Handle)in_mime);
}
else
{
tlMIMEtypeP tlMIME = DegradeMIME(in_mime);
tlAddrListHandle oldAddresses=nil;
if (messH)
ETLBuildOldAddrList(messH,&oldAddresses,ContextRequiresExpansion(context));
MightSwitch();
err = tl_can_translate_file(instance,context,trans_id,tlMIME,nil,oldAddresses,&out_len,out_error,out_code);
AfterSwitch();
DisposeOldTLMIME(tlMIME); // Dispose of copy
DisposeOldAddrList(oldAddresses);
}
return err;
}
/**********************************************************************
* MyTranslateFile - translate a file
**********************************************************************/
static OSErr MyTranslateFile(TLFLPtr pTLFL,long context,short trans_id,
emsMIMEHandle in_mime,FSSpec *in_file, emsMIMEHandle *out_mime,
FSSpec *out_file,Handle *out_icon,StringPtr **out_desc,StringPtr **out_error,
long *out_code, StringHandle queuedProperties, emsHeaderDataP header,
MessHandle messH, Handle translatorName)
{
OSErr err;
tlInstance instance = pTLFL->instance;
Boolean pb = UseParameterBlockStyleFunctions(pTLFL->version);
char hState = 0;
// OpenProgress();
PushProgress();
ProgressMessageR(kpTitle,TRANSLATING);
// right now we'll just set the subTitle to the name of the translator. we may want to include the module description?
hState = HGetState (translatorName);
HLock (translatorName);
ProgressMessage(kpSubTitle,*translatorName);
HSetState (translatorName, hState);
if (pb)
{
emsTranslator trans; /* In: Translator Info */
emsDataFile inTransData; /* In: What to translate */
emsDataFile outTransData; /* Out: Translation retult */
emsResultStatus transStatus; /* Out: Translations Status information */
Zero(trans);
SetSize(trans);
trans.id = trans_id;
trans.properties = queuedProperties;
Zero(inTransData);
SetSize(inTransData);
inTransData.context = context;
inTransData.mimeInfo = in_mime;
inTransData.header = header;
inTransData.file = *in_file;
Zero(outTransData);
SetSize(outTransData);
outTransData.mimeInfo = nil;
outTransData.file = *out_file;
Zero(transStatus);
SetSize(transStatus);
MightSwitch();
err = ems_translate_file(instance,&trans,&inTransData, TO_UPP_OR_NOT_TO_UPP(ETLProgress3), &outTransData,&transStatus);
AfterSwitch();
if (out_desc)
*out_desc = transStatus.desc;
else
ZapHandle(transStatus.desc);
if (out_error)
*out_error = transStatus.error;
else
ZapHandle(transStatus.error);
if (out_code)
*out_code = transStatus.code;
if (out_mime)
*out_mime = outTransData.mimeInfo;
else
DisposeTLMIME(outTransData.mimeInfo);
}
else
{
tlMIMEtypeP outMIME = nil;
tlMIMEtypeP tlMIME = DegradeMIME(in_mime);
tlAddrListHandle oldAddresses=nil;
if (messH)
ETLBuildOldAddrList(messH,&oldAddresses,ContextRequiresExpansion(context));
MightSwitch();
err = tl_translate_file(instance,context,trans_id,tlMIME,in_file,oldAddresses,TO_UPP_OR_NOT_TO_UPP(ETLProgress3),&outMIME,
out_file,out_icon,out_desc,out_error,out_code);
AfterSwitch();
DisposeOldTLMIME(tlMIME); // Dispose of copy
DisposeOldAddrList(oldAddresses);
*out_mime = UpgradeMIME(outMIME);
}
PopProgress(false);
// CloseProgress ();
return err;
}
/**********************************************************************
* ETLSpecial - call a transator's special menu item
**********************************************************************/
OSErr ETLSpecial(short item)
{
emsMenu mInfo;
OSErr err;
Zero(mInfo);
SetSize(mInfo);
mInfo.id = (*TLSpecialList)[item-1].id;
MightSwitch();
err = ems_special_hook((*TLFL)[(*TLSpecialList)[item-1].module].instance,&mInfo);
AfterSwitch();
return(err);
}
/**********************************************************************
* ETLSpecialEnableBasedOnMode - enable transator's special menu items
* based on whether or not they work in the reg mode that Eudora is in
**********************************************************************/
void ETLEnableSpecialItems()
{
MenuHandle hMenu = GetMHandle(SPECIAL_MENU);
short i, n, menuItem;
if (hMenu && TLSpecialList && *TLSpecialList && (n=HandleCount(TLSpecialList)))
{
for (i=0;i<n;i++)
{
menuItem = i+SPECIAL_BAR4_ITEM+1;
if ((*TLFL)[(*TLSpecialList)[i].module].modeNeeded > GetCurrentPayMode ())
{
DisableMenuItemWithProOnlyIcon(hMenu, menuItem);
}
else
{
SetMenuItemIconHandle(hMenu, menuItem, kMenuNoIcon, nil);
EnableItem(hMenu, menuItem);
}
}
}
}
/**********************************************************************
* ETLAttach - call an attachment translator
**********************************************************************/
OSErr ETLAttach(short item,MyWindowPtr win)
{
emsMenu mInfo;
OSErr err;
long numFiles=0;
FSSpec spec;
emsDataFileH dfs=nil;
short i;
Zero(mInfo);
SetSize(mInfo);
mInfo.id = (*TLAttachList)[item-1].id;
if (err=MakeAttSubFolder(Win2MessH(win),SumOf(Win2MessH(win))->uidHash,&spec)) return(err);
MightSwitch();
err=ems_attacher_hook((*TLFL)[(*TLAttachList)[item-1].module].instance,&mInfo,&spec,&numFiles,&dfs);
AfterSwitch();
if (err) return(err);
if (dfs)
{
ASSERT(numFiles==HandleCount(dfs));
for (i=0;i<numFiles;i++)
{
spec = (*dfs)[i].file;
CompAttachSpec(win,&spec);
}
ZapHandle(dfs);
}
return(noErr);
}
/**********************************************************************
* ETLDoSettings - call translators for settings
**********************************************************************/
OSErr ETLDoSettings(short item)
{
OSErr err;
short module = (*TLSettingList)[item-1].module;
TLFuncList tlfl = (*TLFL)[module];
short t;
if (UseOldMailConfig(tlfl.version))
{
emsPre7MailConfig mailConfig;
ETLFillMailConfig(&mailConfig, nil, true);
MightSwitch();
err = ems_plugin_config(tlfl.instance,&mailConfig);
AfterSwitch();
ETLEmptyMailConfig(&mailConfig);
}
else
{
emsCallBack callbacks;
emsMailConfig mailConfig;
ETLFillMailConfig(&mailConfig, &callbacks, false);
MightSwitch();
err = ems_plugin_config(tlfl.instance,&mailConfig);
AfterSwitch();
ETLEmptyMailConfig(&mailConfig);
}
// Call ems_translator_info for each translator to see if flags, icons, etc. have changed
for (t=0;t<tlfl.tCount;t++)
{
TLMaster tlm;
Zero(tlm);
if (UseParameterBlockStyleFunctions(tlfl.version))
{
emsTranslator transInfo;
Zero(transInfo);
SetSize(transInfo);
transInfo.id = t+1;
MightSwitch();
err = ems_translator_info(tlfl.instance,&transInfo);
AfterSwitch();
tlm.type = transInfo.type;
tlm.flags = transInfo.flags;
tlm.nameHandle = transInfo.desc;
tlm.suite = transInfo.icon;
}
// v1
else
{
MightSwitch();
err = tl_translator_info(tlfl.instance,t+1,&tlm.type,nil,&tlm.flags,&tlm.nameHandle,&tlm.suite);
AfterSwitch();
}
if (!err)
{
Handle oldText=nil,suite=nil;
TLMPtr pTLM;
short n;
gTranslatorFlags |= tlm.flags;
// Search for translator in SelList and update fields
for(n=HandleCount(TLSelList),pTLM=*TLSelList+n-1;n--;pTLM--)
if (pTLM->module==module && pTLM->id==t+1)
{
oldText = pTLM->nameHandle;
pTLM->nameHandle = tlm.nameHandle;
pTLM->flags = tlm.flags;
pTLM->type = tlm.type;
if (!suite && tlm.suite)
{
suite = pTLM->suite;
DupIconSuite(tlm.suite,&suite,suite!=nil); // dup the suite, right into the old suite if we have one
DisposeIconSuite(tlm.suite,true); // only dup once
tlm.suite = nil;
pTLM=*TLSelList+n; // update our silly pointer, since might have moved after DisposeIconSuite above
}
pTLM->suite = suite;
break;
}
// Search for translator in Q4List and update fields
for(n=HandleCount(TLQ4List),pTLM=*TLQ4List+n-1;n--;pTLM--)
if (pTLM->module==module && pTLM->id==t+1)
{
if (!oldText) oldText = pTLM->nameHandle;
pTLM->nameHandle = tlm.nameHandle;
pTLM->flags = tlm.flags;
pTLM->type = tlm.type;
if (!suite && tlm.suite)
{
suite = pTLM->suite;
DupIconSuite(tlm.suite,&suite,suite!=nil); // dup the suite, right into the old suite if we have one
DisposeIconSuite(tlm.suite,true); // only dup once
tlm.suite = nil;
pTLM=*TLSelList+n; // update our silly pointer, since might have moved after DisposeIconSuite above
}
pTLM->suite = suite;
break;
}
if (oldText) DisposeHandle(oldText);
}
}
return(err);
}
/**********************************************************************
* QueuedProperties - allow plugin to store properties
**********************************************************************/
OSErr QueuedProperties(short which, long *selected, StringHandle *pProperties,Boolean fDefaultOn)
{
emsTranslator trans;
OSErr err = noErr;
#define pTLFL (&(*TLFL)[(*TLQ4List)[which].module])
if (UseParameterBlockStyleFunctions(pTLFL->version) && ComponentFunctionImplemented(pTLFL->instance,kems_queued_propertiesRtn))
{
Zero(trans);
SetSize(trans);
trans.id = pTLFL->moduleID;
trans.properties = *pProperties;
if (fDefaultOn)
trans.flags = 1; // Indicate that the translator is default on instead of clicked on by the user
MightSwitch();
err = ems_queued_properties(pTLFL->instance,&trans,selected);
AfterSwitch();
//better to leak than crash... if (*pProperties && trans.properties!=*pProperties) ZapHandle(*pProperties); // kill the old one if not still used
if (trans.properties)
{
if (err || !*selected)
ZapHandle(trans.properties); // Translator really should not have returned this handle
else
*pProperties = trans.properties; // Return properties
}
}
else ZapHandle(*pProperties); // get rid of copy of properties
return err;
}
/**********************************************************************
* ETLSelect - user clicked on plugin icon, allow plugin to store properties
**********************************************************************/
OSErr ETLSelect(short which, Boolean selecting, MessHandle messH)
{
long selected;
StringHandle properties;
OSErr result;
properties = selecting ? nil :
// Deselecting. Get any existing queued properties
GetQueuedProperties(messH,ETLIconToID(which));
if (properties) properties = DupHandle(properties); // protect our handle
selected = selecting;
result = QueuedProperties(which, &selected, &properties, false);
if (selecting)
{
if (selected)
AddMessTranslator(messH,which,properties);
}
else
{
RemoveMessTranslator(messH,which);
if (selected)
AddMessTranslator(messH,which,properties);
}
return result;
}
/**********************************************************************
* ETLGetPluginFolderSpec - return filespec for a folder in plugin filters folder
**********************************************************************/
OSErr ETLGetPluginFolderSpec(FSSpec *spec,short nameId)
{
Str255 s;
OSErr err;
if (!(err = FSMakeFSSpec(ItemsFolder.vRef,ItemsFolder.dirId,GetRString(s,PLUGINS_FOLDER),spec)))
{
IsAlias(spec,spec);
if (nameId)
{
err = FSMakeFSSpec(spec->vRefNum,SpecDirId(spec),GetRString(s,nameId),spec);
IsAlias(spec,spec);
}
}
return err;
}
/**********************************************************************
* UpgradeMIME - Convert from older mime structure in place
**********************************************************************/
static emsMIMEHandle UpgradeMIME(tlMIMEtypeP inMIME)
{
emsMIMEHandle outMIME = (emsMIMEHandle)inMIME;
if (inMIME)
{
emsMIMEtype tempMIME;
tlMIMEtype *pInMIME;
tlMIMEParamP hParam;
// Convert MIME info to newer data structure
SetHandleSize((Handle)inMIME,sizeof(emsMIMEtype)); // Need to enlarge for larger structure
if (MemError())
return nil; // Error, don't return anything
pInMIME = *inMIME;
Zero(tempMIME);
SetSize(tempMIME);
BMD(pInMIME->mime_version,tempMIME.mimeVersion,sizeof(tempMIME.mimeVersion));
BMD(pInMIME->mime_type,tempMIME.mimeType,sizeof(tempMIME.mimeType));
BMD(pInMIME->sub_type,tempMIME.subType,sizeof(tempMIME.subType));
hParam = pInMIME->params;
tempMIME.params = (emsMIMEparamH)hParam;
BMD(&tempMIME,*inMIME,sizeof(tempMIME));
// Now convert any parameters to newer data structure
while (hParam)
{
tlMIMEparam *pParam;
emsMIMEparam tempParam;
SetHandleSize((Handle)hParam,sizeof(emsMIMEparam)); // Need to enlarge for larger structure
if (MemError())
return nil; // Error, don't return anything
pParam = *hParam;
SetSize(tempParam);
BMD(pParam->name,tempParam.name,sizeof(tempParam.name));
tempParam.value = pParam->value;
hParam = pParam->next;
tempParam.next = (emsMIMEparamH)hParam;
BMD(&tempParam,pParam,sizeof(tempParam));
}
}
return outMIME;
}
/* Junk Stuff */
OSErr ETLScoreJunk ( TLMPtr thePlugin,
emsTranslatorP transInfo, /* In: Translator Info */
emsJunkInfoP junkInfo, /* In: Junk information */
emsMessageInfoP messageInfo, /* In: Message to score */
emsJunkScoreP junkScore, /* Out: Junk score */
emsResultStatusP junkStatus /* Out: Status information */
) {
return ems_score_junk ( (*TLFL)[ thePlugin->module].instance, transInfo, junkInfo, messageInfo, junkScore, junkStatus );
}
/* Junk Stuff */
OSErr ETLMarkJunk ( TLMPtr thePlugin,
emsTranslatorP transInfo, /* In: Translator Info */
emsJunkInfoP junkInfo, /* In: Junk information */
emsMessageInfoP messageInfo, /* In: Message to score */
emsJunkScoreP junkScore, /* Out: Junk score */
emsResultStatusP junkStatus /* Out: Status information */
) {
return ems_user_mark_junk ( (*TLFL)[ thePlugin->module].instance, transInfo, junkInfo, messageInfo, junkScore, junkStatus );
}
/**********************************************************************
* DegradeMIMEParam - Convert to older mime paramater structure. Returns a copy.
**********************************************************************/
static tlMIMEParamP DegradeMIMEParam(emsMIMEparamH hParam)
{
tlMIMEParamP hResult = nil;
if (hParam && (hResult = NuHandle(sizeof(tlMIMEparam))))
{
BMD((*hParam)->name,(*hResult)->name,sizeof((*hResult)->name));
(*hResult)->value = (*hParam)->value; // We didn't make a copy of this so don't dispose of it!!!
(*hResult)->next = DegradeMIMEParam((*hParam)->next); // Recurse
}
return hResult;
}
/**********************************************************************
* DegradeMIME - Convert to older mime structure. Returns a copy.
**********************************************************************/
static tlMIMEtypeP DegradeMIME(emsMIMEHandle inMIME)
{
tlMIMEtypeP outMIME = nil;
if (inMIME && (outMIME = NuHandle(sizeof(tlMIMEtype))))
{
// Convert MIME info to older data structure
BMD((*inMIME)->mimeVersion,(*outMIME)->mime_version,sizeof((*outMIME)->mime_version));
BMD((*inMIME)->mimeType,(*outMIME)->mime_type,sizeof((*outMIME)->mime_type));
BMD((*inMIME)->subType,(*outMIME)->sub_type,sizeof((*outMIME)->sub_type));
(*outMIME)->params = DegradeMIMEParam((*inMIME)->params);
}
return outMIME;
}
/**********************************************************************
* GetQueuedProperties - Find queued properties from message
**********************************************************************/
static StringHandle GetQueuedProperties(MessHandle messH,long id)
{
TransInfoHandle translators = (*messH)->hTranslators;
short i;
if (translators)
for (i=HandleCount(translators);i--;)
if ((*translators)[i].id==id)
return (*translators)[i].properties;
return nil;
}
/************************************************************************
* Modeless EMSAPI stuff
************************************************************************/
/************************************************************************
* IsPlugwindow - is something a plugin window?
************************************************************************/
Boolean IsPlugwindow(WindowPtr theWindow)
{
return(theWindow && GetWindowKind(theWindow)==EMS_PW_WINDOWKIND);
}
/************************************************************************
* IsModalPlugwindow - is something a plugin window that wants to
* be non-blocking modal?
************************************************************************/
Boolean IsModalPlugwindow(WindowPtr theWindow)
{
Boolean isModalPlugwindow = false;
if (theWindow && GetWindowKind(theWindow)==EMS_PW_WINDOWKIND)
{
long refCon = GetWRefCon(theWindow);
if (refCon != 0)
{
emsPlugwindowDataP wdPtr = *(emsPlugwindowDataH)refCon;
// If the plugin is new enough then check the emsPlugwindowData
if (wdPtr->size > (&wdPtr->isDialogLayer - wdPtr))
isModalPlugwindow = wdPtr->isDialogLayer;
}
}
return isModalPlugwindow;
}
/************************************************************************
* IsNonModalPlugwindow - is something a plugin window that wants to
* be normal (i.e. not non-blocking modal)?
************************************************************************/
Boolean IsNonModalPlugwindow(WindowPtr theWindow)
{
return (IsPlugwindow(theWindow) && !IsModalPlugwindow(theWindow));
}
/************************************************************************
* PlugwindowEventFilter - filter an event for a plugin window
************************************************************************/
Boolean PlugwindowEventFilter(EventRecord *event)
{
emsPlugwindowData wd;
short module;
emsPlugwindowEvent ed;
WindowPtr theWindow = nil;
Boolean result=true;
switch(event->what)
{
case updateEvt:
case activateEvt:
theWindow = Event2Window(event);
break;
case mouseDown:
case mouseUp:
// If modal window is frontmost and if it's not a dialog modal window, then bail
FindWindow(event->where,&theWindow);
if ( ModalWindow && ((ModalWindow != theWindow) || !IsModalPlugwindow(theWindow)) )
return(true);
break;
}
if (!theWindow) theWindow = MyFrontNonFloatingWindow();
if (IsPlugwindow(theWindow))
{
long refCon = GetWRefCon(theWindow);
if (refCon != 0)
{
wd = **(emsPlugwindowDataH)refCon;
SetSize(wd);
if (PluginIDToIndex(wd.pluginID,&module))
{
Zero(ed);
SetSize(ed);
ed.nativeEvent = event;
//Dprintf("\pem %x win %x wd.nativeWindow %x pID %d m %d;g",event->message,win,wd.nativeWindow,wd.pluginID,module);
result = 0!=ems_plugwindow_event((*TLFL)[module].instance,&wd,&ed);
}
}
}
return(result);
}
/************************************************************************
* PlugwindowEnable - grab flags for plugwindow enabling
************************************************************************/
void PlugwindowEnable(WindowPtr theWindow,long *flags)
{
long refCon = GetWRefCon(theWindow);
if (refCon != 0)
{
emsPlugwindowData wd = **(emsPlugwindowDataH)refCon;
short module;
emsMenuData md;
*flags = 0;
if (PluginIDToIndex(wd.pluginID,&module))
{
Zero(md);
SetSize(md);
SetSize(wd);
ems_plugwindow_menu_enable((*TLFL)[module].instance,&wd,&md);
*flags = md.menuMask;
}
}
}
/************************************************************************
* PlugwindowMenu - do a menu command for a plugin window
************************************************************************/
Boolean PlugwindowMenu(WindowPtr theWindow,long select)
{
long refCon = GetWRefCon(theWindow);
if (refCon != 0)
{
emsPlugwindowData wd = **(emsPlugwindowDataH)refCon;
short module;
emsMenuData md;
Zero(md);
SetSize(md);
switch(select)
{
case (FILE_MENU<<16)|FILE_CLOSE_ITEM: md.menuMask = EMS_MENU_FILE_CLOSE; break;
case (FILE_MENU<<16)|FILE_SAVE_ITEM: md.menuMask = EMS_MENU_FILE_SAVE; break;
case (EDIT_MENU<<16)|EDIT_UNDO_ITEM: md.menuMask = EMS_MENU_EDIT_UNDO; break;
case (EDIT_MENU<<16)|EDIT_CUT_ITEM: md.menuMask = EMS_MENU_EDIT_CUT; break;
case (EDIT_MENU<<16)|EDIT_COPY_ITEM: md.menuMask = EMS_MENU_EDIT_COPY; break;
case (EDIT_MENU<<16)|EDIT_PASTE_ITEM: md.menuMask = EMS_MENU_EDIT_PASTE; break;
case (EDIT_MENU<<16)|EDIT_CLEAR_ITEM: md.menuMask = EMS_MENU_EDIT_CLEAR; break;
case (EDIT_MENU<<16)|EDIT_SELECT_ITEM: md.menuMask = EMS_MENU_EDIT_SELECTALL; break;
default: return(false);
}
if (PluginIDToIndex(wd.pluginID,&module))
{
SetSize(wd);
return(!ems_plugwindow_menu((*TLFL)[module].instance,&wd,&md));
}
}
return(false);
}
/************************************************************************
* PlugwindowClose - close a plug-in window
************************************************************************/
Boolean PlugwindowClose(WindowPtr theWindow)
{
Boolean windowWasClosed = false;
long refCon = GetWRefCon(theWindow);
if (refCon != 0)
{
emsPlugwindowData wd = **(emsPlugwindowDataH)refCon;
short module;
if (PluginIDToIndex(wd.pluginID,&module))
{
SetSize(wd);
windowWasClosed = !ems_plugwindow_close((*TLFL)[module].instance,&wd);
}
else
{
DisposeWindow(theWindow);
windowWasClosed = true;
}
}
else
{
DisposeWindow(theWindow);
windowWasClosed = true;
}
// PopModalWindow and setting lastHilitedWinWP to 0 if necessary
// should have already been done in ETLPlugwindowUnRegister.
// Check to see if we need to do either of these now in case the
// plugin didn't call ETLPlugwindowUnRegister, or we had to close the
// window ourselves.
if (IsModalPlugwindow(theWindow) && (theWindow == ModalWindow))
PopModalWindow();
#ifdef FLOAT_WIN
if (theWindow == lastHilitedWinWP) lastHilitedWinWP = 0;
#endif //FLOAT_WIN
return (windowWasClosed);
}
/************************************************************************
* PlugwindowDrag - drag tracking in a plugwindow
************************************************************************/
OSErr PlugwindowDrag(WindowPtr theWindow,DragTrackingMessage message,DragReference drag)
{
long refCon = GetWRefCon(theWindow);
if (refCon != 0)
{
emsPlugwindowData wd = **(emsPlugwindowDataH)refCon;
emsPlugwindowDragData pd;
short module;
if (PluginIDToIndex(wd.pluginID,&module))
{
SetSize(wd);
Zero(pd);
SetSize(pd);
pd.drag = drag;
pd.message = message;
return(ems_plugwindow_drag((*TLFL)[module].instance,&wd,&pd));
}
}
return(dragNotAcceptedErr);
}
/************************************************************************
* PlugwindowSendFakeEvent - only call for plugin windows
************************************************************************/
void PlugwindowSendFakeEvent(WindowPtr theWindow, UInt32 message, EventKind what, EventModifiers modifiers, Point * where)
{
short module;
emsPlugwindowEvent ed;
EventRecord event;
long refCon = GetWRefCon(theWindow);
if (refCon != 0)
{
emsPlugwindowData wd = **(emsPlugwindowDataH)refCon;
SetSize(wd);
if (PluginIDToIndex(wd.pluginID,&module))
{
Zero(event);
event.what = what;
event.message = message;
event.modifiers = modifiers;
if (where)
event.where = *where;
Zero(ed);
SetSize(ed);
ed.nativeEvent = &event;
ems_plugwindow_event((*TLFL)[module].instance,&wd,&ed);
}
}
}
/************************************************************************
* PlugwindowActivate -
************************************************************************/
void PlugwindowActivate(WindowPtr theWindow, Boolean active)
{
if (IsPlugwindow(theWindow))
{
#ifdef FLOAT_WIN
HiliteWindow(theWindow,active);
#endif //FLOAT_WIN
PlugwindowSendFakeEvent(theWindow, (long)theWindow, activateEvt, active ? activeFlag : 0, nil);
}
}
/************************************************************************
* PlugwindowUpdate - if a window is a plugin window, update it
************************************************************************/
void PlugwindowUpdate(WindowPtr theWindow)
{
if (IsPlugwindow(theWindow))
PlugwindowSendFakeEvent(theWindow, (long)theWindow, updateEvt, 0, nil);
}
/***************************************************************************
* ETLCreateMailBox - Callback to create a mailbox, but not for the importers
***************************************************************************/
static pascal short ETLCreateMailBox(emsCreateMailBoxDataP makeMailboxData)
{
FSSpec folderSpec;
FSSpec createdSpec;
OSErr err = noErr;
SLDisable();
SetSize(*makeMailboxData);
// Where do we make it?
if (makeMailboxData->parentFolder)
{
err = SimpleResolveAlias(makeMailboxData->parentFolder,&folderSpec);
if (!err) folderSpec.parID = SpecDirId(&folderSpec);
}
else
{
folderSpec.vRefNum = MailRoot.vRef;
folderSpec.parID = MailRoot.dirId;
}
if (!err)
{
// What do we call it?
err = FSMakeFSSpec(folderSpec.vRefNum,folderSpec.parID,makeMailboxData->name,&createdSpec);
// die if something went wrong
if (!err)
{
// It exists, check to see if it's what the caller expected
Boolean isFolder, boolJunk;
err = ResolveAliasFile(&createdSpec, True, &isFolder, &boolJunk);
if ( !err && (isFolder != makeMailboxData->createFolder) )
err = dupFNErr;
}
else if (err==fnfErr)
{
// Make it
if (err=BadMailboxName(&createdSpec, makeMailboxData->createFolder)) err = bdNamErr;
if (!err)
{
// let the menus and mailboxes window know about it
BuildBoxMenus();
MBTickle(nil,nil);
// Make an alias to it
FSMakeFSSpec(MailRoot.vRef, MailRoot.dirId, "", &folderSpec);
NewAlias(&folderSpec, &createdSpec, &makeMailboxData->mailboxOrFolder);
}
}
}
SLEnable();
// We be done
return (err);
}
/***************************************************************************
* ETLIsInAddressBook - Callback to create a mailbox, but not for the importers
***************************************************************************/
static pascal short ETLIsInAddressBook(emsIsInAddressBookDataP makeMailboxData)
{
// To do: Marshall - please implement.
return unimpErr;
}
/************************************************************************
* Import Plugin support
************************************************************************/
/**********************************************************************
* ETLImport - call the importer with the spcified ID
**********************************************************************/
OSErr ETLImport(long id, ImportOperationEnum what, void *params, void *results)
{
OSErr err = noErr;
emsImporterData data;
TLMPtr importer;
tlInstance instance;
//
// find the importer
//
if (TLImporterList)
{
importer = &((*TLImporterList)[id]);
if (importer)
{
instance = (&(*TLFL)[importer->module])->instance;
if (!(err=!ComponentFunctionImplemented(instance,kems_importer_hookRtn)))
{
//
// make the call
//
SetSize(data);
data.what = what;
data.params = params;
data.results = results;
PushProgress();
err = ems_importer_hook(instance,&data);
PopProgress(false);
}
}
else // no importer with that id
err = TLR_CANT_TRANS;
}
else // no importer translator handle
err = TLR_CANT_TRANS;
return (err);
}
/***************************************************************************
* ETLQueryImporters - check importer plugins and see what can be imported
***************************************************************************/
OSErr ETLQueryImporters(ImportAccountInfoH *results, long id, Boolean search)
{
OSErr err = noErr;
short i, j;
if (TLImporterList)
{
// Loop through all importers and call the Query function
for (i=HandleCount(TLImporterList);i--;)
{
if ((id == kUnspecifiedImportPluginId) || (id == i))
{
err = ETLImport(i, search?EMS_IMPORT_Query:EMS_IMPORT_Name_Query, (void *)TO_UPP_OR_NOT_TO_UPP(ETLProgress3), (void *)(results));
if (err) ImportError(i, kImportSetupErr, kImportQueryError, err, __LINE__);
// go through and fill in the id field of al new results
for (j=HandleCount(*results);j--;)
if ((**results)[j].id == -1)
(**results)[j].id = i;
}
}
}
else // no importer translator handle
{
err = TLR_CANT_TRANS;
ImportError(kUnspecifiedImportPluginId, kImportSetupErr, kImportMemError, err, __LINE__);
}
return (err);
}
/***************************************************************************
* GetImporterAppIcon - return a handle to the impoter's app icon
***************************************************************************/
Handle GetImporterAppIcon(long id)
{
Handle suite = nil;
if (TLImporterList)
if (id <= HandleCount(TLImporterList))
suite = (*TLImporterList)[id].suite;
return (suite);
}
/***************************************************************************
* GetImporterName - return the name of an importer
***************************************************************************/
void GetImporterName(long id, Str255 name)
{
name[0] = 0;
if (TLImporterList)
if (id <= HandleCount(TLImporterList))
PCopy(name,*(*TLImporterList)[id].nameHandle);
}
/************************************************************************
* ETLImportSignatures - Import an account's signatures
************************************************************************/
OSErr ETLImportSignatures(ImportAccountInfoP account)
{
ImportSignaturesDataS makeSigData;
Zero(makeSigData);
SetSize(makeSigData);
makeSigData.importSpec = account->importSpec;
makeSigData.makeSig = TO_UPP_OR_NOT_TO_UPP(ETLMakeSig);
makeSigData.progress = TO_UPP_OR_NOT_TO_UPP(ETLProgress3);
return (ETLImport(account->id, EMS_IMPORT_Signatures, &makeSigData, nil));
}
/************************************************************************
* ETLImportAddresses - Import an account's address book(s)
************************************************************************/
OSErr ETLImportAddresses(ImportAccountInfoP account)
{
ImportAddressDataS addressImportData;
Zero(addressImportData);
SetSize(addressImportData);
addressImportData.importSpec = account->importSpec;
PCopy(addressImportData.accountName, account->accountName);
addressImportData.makeAddressBook = TO_UPP_OR_NOT_TO_UPP(ETLMakeAddressBook);
addressImportData.makeABEntry = TO_UPP_OR_NOT_TO_UPP(ETLMakeABEntry);
addressImportData.progress = TO_UPP_OR_NOT_TO_UPP(ETLProgress3);
return (ETLImport(account->id, EMS_IMPORT_Addresses, &addressImportData, nil));
}
/************************************************************************
* ETLImportMail - Import an account's messages and mailboxes
************************************************************************/
OSErr ETLImportMail(ImportAccountInfoP account)
{
ImportMailDataS mailImportData;
Zero(mailImportData);
SetSize(mailImportData);
mailImportData.importSpec = account->importSpec;
PCopy(mailImportData.accountName, account->accountName);
mailImportData.makeMailbox = TO_UPP_OR_NOT_TO_UPP(ETLMakeMailbox);
mailImportData.makeOutMess = TO_UPP_OR_NOT_TO_UPP(ETLMakeOutMess);
mailImportData.makeMessage = TO_UPP_OR_NOT_TO_UPP(ETLMakeMessage);
mailImportData.progress = TO_UPP_OR_NOT_TO_UPP(ETLProgress3);
mailImportData.importMBox = TO_UPP_OR_NOT_TO_UPP(ETLImportMbox);
return (ETLImport(account->id, EMS_IMPORT_Mail, &mailImportData, nil));
}
/************************************************************************
* ETLImportSettings - Import an account's settings
************************************************************************/
OSErr ETLImportSettings(ImportAccountInfoP account, ImportPersDataH *persData)
{
OSErr err = noErr;
*persData = NuHandle(0L);
err = MemError();
if ((err == noErr) && *persData && **persData)
{
err = ETLImport(account->id, EMS_IMPORT_Settings, &(account->importSpec), persData);
if (err != noErr)
{
// an error occurred importing settings information
ImportError(account->id, kImportSettingsErr, kImportSettingsError, err=eofErr, __LINE__);
ZapHandle(*persData);
}
}
else
{
// a memory related error occurred.
ImportError(kUnspecifiedImportPluginId, kImportSettingsErr, kImportMemError, err, __LINE__);
}
return (err);
}
/***************************************************************************
* ETLMakeSig - Callback to create a signature file
***************************************************************************/
static pascal short ETLMakeSig(emsMakeSigDataP makeSigData)
{
short returnMe;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
returnMe = (ImportMakeNewSigCalback(makeSigData->name, makeSigData->sigText));
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return returnMe;
}
/***************************************************************************
* ETLImportMbox - Callback to import mail from an mbox file
***************************************************************************/
static pascal short ETLImportMbox(emsImportMboxDataP importMBoxData)
{
short returnMe;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
returnMe = ImportMboxCallback ( &importMBoxData->sourceMBox, &importMBoxData->boxSpec );
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return returnMe;
}
/***************************************************************************
* ETLMakeAddressBook - Callback to create an address book file
***************************************************************************/
static pascal short ETLMakeAddressBook(emsMakeAddressBookDataP makeAddressBookData)
{
short returnMe;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
returnMe = (ImportMakeAddressBookCallback(makeAddressBookData->name));
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return returnMe;
}
/***************************************************************************
* ETLMakeABEntry - Callback to create an address book entry
***************************************************************************/
static pascal short ETLMakeABEntry(emsMakeABEntryDataP makeABEntryData)
{
short returnMe;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
returnMe = (ImportMakeABEntryCallback(makeABEntryData->which, makeABEntryData->isGroup, makeABEntryData->nickName, makeABEntryData->addresses, makeABEntryData->notes));
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return returnMe;
}
/***************************************************************************
* ETLMakeMailbox - Callback to create a mailbox
***************************************************************************/
static pascal short ETLMakeMailbox(emsMakeMailboxDataP makeMailboxData)
{
short returnMe;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
returnMe = (ImportMakeMailboxCallback(makeMailboxData->command, &(makeMailboxData->boxSpec), makeMailboxData->isFolder, makeMailboxData->noSelect));
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return returnMe;
}
/***************************************************************************
* ETLMakeOutMess - Callback to create an outgoing message
***************************************************************************/
static pascal short ETLMakeOutMess(emsMakeOutMessDataP makeOutMessData)
{
short returnMe;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
returnMe = (ImportMakeOutMessCallback(makeOutMessData));
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return returnMe;
}
/***************************************************************************
* ETLMakeMessage - Callback to create an outgoing message
***************************************************************************/
static pascal short ETLMakeMessage(emsMakeMessageDataP makeMessageData)
{
short returnMe;
SLDisable(); // Spotlight doesn't like emsapi callbacks, alas
returnMe = (ImportMessageCallback(makeMessageData->ref, makeMessageData->offset, makeMessageData->len, makeMessageData->state, makeMessageData->attachments, &(makeMessageData->boxSpec)));
SLEnable(); // Spotlight doesn't like emsapi callbacks, alas
return returnMe;
}
#endif
#if TARGET_RT_MAC_CFM
/* For old-style calls to components */
enum {
uppCallComponentProcInfo = kPascalStackBased
| RESULT_SIZE(kFourByteCode)
| STACK_ROUTINE_PARAMETER(1, kFourByteCode)
};
/* This global takes the routine parameters for each component function call */
tl_ComponentParameters tl_GCP;
/* Routine to put a copy of the component params on the stack and calls
CallComponentUPP */
ComponentResult Calltl_ComponentFunction(tl_ComponentParameters params)
{
return CallComponentDispatch(/*tl_GCP.params.ems_translate_file.globals,*/&params);
}
/* This global takes the routine parameters for each component function call */
ems_ComponentParameters ems_GCP;
/* Routine to put a copy of the component params on the stack and calls
CallComponentUPP */
ComponentResult Callems_ComponentFunction(ems_ComponentParameters params)
{
return CallComponentDispatch(/*ems_GCP.params.ems_translate_file.globals,*/&params);
}
#endif
#endif