/* 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>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;tmem_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;i31) *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;icallBacks; } 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 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;ivalue; 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;tsize = 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 && offsetcount < 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;sigIdxspec.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>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;iextras.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;ivRefNum,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 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;imodule==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,*/¶ms); } /* 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,*/¶ms); } #endif #endif