eudora-mac/schizo.c

1 line
28 KiB
C
Executable File

/* Copyright (c) 2017, Computer History Museum
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to
the limitations in the disclaimer below) provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE. */
#include "schizo.h"
#define FILE_NUM 82
/* Copyright (c) 1996 by QUALCOMM Incorporated */
static int PersCompare(PersHandle *p1, PersHandle *p2);
static void PersSwap(PersHandle *n1, PersHandle *n2);
static void UpdatePersList(void);
#pragma segment Main
typedef struct
{
PropToken property;
PersHandle pers;
} PersSpecifier;
/**********************************************************************
* PersAnyPasswords - do we have any passwords?
**********************************************************************/
Boolean PersAnyPasswords(void)
{
PersHandle pers;
for (pers=PersList;pers;pers=(*pers)->next)
if (*(*pers)->password || *(*pers)->secondPass) return(True);
return(False);
}
#pragma segment Schizo
/**********************************************************************
* PersFillPw - grab passwords for a personality
**********************************************************************/
OSErr PersFillPw(PersHandle pers,uLong whichOnes)
{
Str255 s;
OSErr err = noErr;
Str127 uName, hName, persName;
*s = 0;
#ifdef HAVE_KEYCHAIN
if (PrefIsSet(PREF_KEYCHAIN))
{
err = FindPersKCPassword(pers,s,sizeof(s));
if (err==userCanceledErr) return err;
PSCopy((*pers)->password,s);
}
#endif //HAVE_KEYCHAIN
if (!*(*pers)->password)
{
GetPassStuff(persName,uName,hName);
GetPassword(persName,uName,hName,s,sizeof(s),ENTER);
(*pers)->dirty = true;
PSCopy((*pers)->password,s);
if (*s)
{
if (PrefIsSet(PREF_SAVE_PASSWORD)) PersSavePw(pers);
PSCopy((*pers)->password,s); // savepw wipes it out; put it back, for now
}
}
return(*(*pers)->password ? noErr:userCanceledErr);
}
/**********************************************************************
* PersSavePw - save passwords for a personality
**********************************************************************/
OSErr PersSavePw(PersHandle pers)
{
OSErr err = noErr;
Str31 pass, secondPass;
Str255 scratch;
#ifdef HAVE_KEYCHAIN
if (KeychainAvailable() && PrefIsSet(PREF_KEYCHAIN))
{
err = UpdatePersKCPassword(pers);
WriteZero((*pers)->password,sizeof((*pers)->password));
}
else
#endif //HAVE_KEYCHAIN
if (pers==PersList)
{
PSCopy(pass,(*PersList)->password);
PSCopy(secondPass,(*PersList)->secondPass);
if (!EqualString(pass,GetPref(scratch,PREF_PASS_TEXT),True,True) ||
!EqualString(secondPass,GetPref(scratch,PREF_AUXPW),True,True))
{
SetPref(PREF_PASS_TEXT,pass);
SetPref(PREF_AUXPW,secondPass);
MyUpdateResFile(SettingsRefN);
}
}
else
{
err = PersSave(pers);
}
return(err);
}
/**********************************************************************
* PersSaveAll - save all personalities
**********************************************************************/
OSErr PersSaveAll(void)
{
OSErr err=noErr;
PersHandle pers;
Boolean multiplePersonalities = false;
for (pers=PersList;pers;pers=(*pers)->next)
if (err=PersSave(pers)) break;
return(err);
}
/**********************************************************************
*
**********************************************************************/
OSErr PersSave(PersHandle pers)
{
OSErr err = noErr;
Str63 scratch;
PersHandle oldCur = CurPers;
Str63 oldPass;
*oldPass = 0;
if ((*pers)->dirty && (*pers)->resId)
{
// swap personality into current
CurPers = pers;
// make sure we don't unintentionally save the password
if (!PrefIsSet(PREF_SAVE_PASSWORD))
{
PSCopy(oldPass,(*pers)->password);
WriteZero(LDRef(pers)->password,sizeof((*pers)->password));
UL(pers);
}
#ifdef HAVE_KEYCHAIN
else if (KeychainAvailable() && PrefIsSet(PREF_KEYCHAIN))
{
WriteZero((*pers)->password,sizeof((*pers)->password));
}
#endif //HAVE_KEYCHAIN
// remove old, add new
ZapResource(PERS_RTYPE,(*pers)->resId);
AddMyResource((Handle)pers,PERS_RTYPE,(*pers)->resId,"");
if (!(err=ResError()))
{
err = MyUpdateResFile(SettingsRefN);
DetachResource((Handle)pers);
}
if (!err) (*pers)->dirty = False;
else
{
PSCopy(scratch,(*pers)->name);
Aprintf(OK_ALRT,err,PERS_SAVE_ERR,scratch);
}
// put stuff back
CurPers = oldCur;
if (*oldPass) PSCopy((*pers)->password,oldPass);
}
return(err);
}
/**********************************************************************
* PersNew - create a new personality
**********************************************************************/
PersHandle PersNew(void)
{
PersHandle pers, newPers=nil;
short n;
short resEnd;
Str63 untitled;
UseFeature (featureMultiplePersonalities);
// find an unused name
for (n=PersCount()+1;;n++)
{
GetRString(untitled,UNTITLED);
PLCat(untitled,n);
if (!FindPersByName(untitled)) break;
}
// Allocate the last couple bytes of resource id's
n = 0;
do
{
n++;
Bytes2Hex(((UPtr)&n)+1,1,(UPtr)&resEnd);
for (pers=(*PersList)->next;pers;pers=(*pers)->next)
if ((*pers)->resEnd==resEnd) break;
}
while (pers);
// out of personalities?
if (n>100) {WarnUser(YOU_ARE_PSYCHO,0);return(nil);}
// create the personality
if (newPers=NewZH(Personality))
{
PersSetName(newPers,untitled);
n = MyUniqueID(PERS_RTYPE);
(*newPers)->resId = n;
(*newPers)->resEnd = resEnd;
PersSave(newPers);
LL_Queue(PersList,newPers,(PersHandle));
PersZapResources('STR ',resEnd);
PushPers(CurPers);
CurPers = newPers;
SetStrOverride(PREF3_STRN+PREF_STUPID_USER%100,"");
SetStrOverride(PREF3_STRN+PREF_STUPID_HOST%100,"");
PopPers();
UpdatePersList();
}
else
WarnUser(MEM_ERR,MemError());
return(newPers);
}
/**********************************************************************
* PersDelete - kill a personality
**********************************************************************/
OSErr PersDelete(PersHandle pers)
{
if (HasFeature (featureMultiplePersonalities))
{
if (pers==PersList) return(errAENotModifiable);
UseFeature (featureMultiplePersonalities);
#ifdef HAVE_KEYCHAIN
if (KeychainAvailable() && PrefIsSet(PREF_KEYCHAIN))
{
DeletePersKCPassword(pers);
}
#endif //HAVE_KEYCHAIN
LL_Remove(PersList,pers,(PersHandle));
ZapSettingsResource(PERS_RTYPE,(*pers)->resId);
PersZapResources('STR ',(*pers)->resEnd);
UpdatePersList();
AuditPersDelete((*pers)->persId);
}
return(noErr);
}
/**********************************************************************
* PersZapResources - zap resources for a personality
**********************************************************************/
void PersZapResources(OSType type,short resEnd)
{
Handle res;
// Kill old resources
type = PERS_TYPE(type,resEnd);
while (res=Get1IndResource(type,1)) {RemoveResource(res); if (!ResError()) DisposeHandle(res);}
}
/**********************************************************************
* PersType - find an alternate type for a resource based on the personality
**********************************************************************/
OSType PersType(OSType theType,PersHandle pers)
{
if (pers && (*pers)->persId)
theType = (theType&0xffff0000) | (*pers)->resEnd;
return(theType);
}
/**********************************************************************
* FindPersById - find a personality, given a personality id
**********************************************************************/
PersHandle FindPersById(uLong persId)
{
PersHandle pers;
for (pers=PersList;pers;pers=(*pers)->next)
if ((*pers)->persId==persId) break;
return(pers);
}
/**********************************************************************
* FindPersById - find a personality, given a personality name
**********************************************************************/
PersHandle FindPersByName(PStr name)
{
if (EqualStrRes(name,DOMINANT)) return(PersList);
return(FindPersById(Hash(name)));
}
#pragma segment Ends
/**********************************************************************
* InitPersonalities - read personalities into the personality queue
**********************************************************************/
void InitPersonalities(void)
{
PersHandle pers = NewZH(Personality);
Str63 dom;
uLong ticks = TickCount();
long hash;
short n;
Boolean multiplePersonalities = false;
/*
* first, the dominant personality
*/
if (!pers) DieWithError(MEM_ERR,MemError());
LL_Queue(PersList,pers,(PersHandle));
GetRString(dom,DOMINANT);
PSCopy((*pers)->name,dom);
#ifdef IMAP
(*pers)->mailboxTree = 0;
(*pers)->imapRefresh = 0;
#endif
CurPers = pers;
/*
* Next, any others
*/
if (HasFeature (featureMultiplePersonalities)) {
for (n=1;pers=(PersHandle)Get1IndResource(PERS_RTYPE,n);n++)
{
if (!*pers || !GetHandleSize(pers))
{
RemoveResource(pers);
if (!ResError()) n--; // removed one, retry
ZapHandle(pers);
}
else if ((*pers)->version > PERS_VERS)
ReleaseResource((Handle)pers);
else
{
DetachResource((Handle)pers);
SetHandleBig((Handle)pers,sizeof(Personality));
if (MemError()) DieWithError(MEM_ERR,MemError());
(*pers)->next = nil;
LL_Queue(PersList,pers,(PersHandle));
(*pers)->dirty = False;
(*pers)->checkTicks = 0;
(*pers)->proxy = nil;
#ifdef IMAP
(*pers)->mailboxTree = 0;
(*pers)->imapRefresh = 0;
#endif
// The popd resources shouldn't be here if this is
// an imap personality. Kill them.
if (IsIMAPPers(pers))
{
ZapResource(PERS_POPD_TYPE(pers),POPD_ID);
ZapResource(PERS_POPD_TYPE(pers),DELETE_ID);
ZapResource(PERS_POPD_TYPE(pers),FETCH_ID);
}
if (pers!=PersList)
{
PSCopy(dom,(*pers)->name);
hash = Hash(dom);
ASSERT(hash==(*pers)->persId);
(*pers)->persId = hash;
// make sure we commit this particular setting
PushPers(pers);
GetPrefNoDominant(dom,PREF_SUBMISSION_PORT);
if (!*dom) SetPref(PREF_SUBMISSION_PORT,NoStr);
PopPers();
}
}
}
if (n > 1)
UseFeature (featureMultiplePersonalities);
UpdatePersList();
}
CurPers = PersList; // let's make sure, shall we?
return;
}
/**********************************************************************
* PushPers - push current personality on the stack and set
**********************************************************************/
void PushPers(PersHandle newCur)
{
if (PersStack || !StackInit(sizeof(PersHandle),&PersStack))
StackPush(&CurPers,PersStack);
if (newCur) CurPers = newCur;
}
/**********************************************************************
* PopPers - pop the top personality off the stack and set
**********************************************************************/
void PopPers(void)
{
ASSERT(PersStack && (*PersStack)->elCount);
if (PersStack) StackPop(&CurPers,PersStack);
}
/**********************************************************************
* PersSetName - set the name of a personality
**********************************************************************/
OSErr PersSetName(PersHandle pers,PStr name)
{
uLong hash = Hash(name);
PersHandle oldPers;
if (oldPers=FindPersByName(name))
{
if (pers==oldPers) return(noErr);
else return(WarnUser(USED_PERSONALITY,dupFNErr));
}
PSCopy((*pers)->name,name);
if ((*pers)->persId)
AuditPersRename((*pers)->persId,hash);
else
AuditPersCreate(hash);
(*pers)->persId = hash;
(*pers)->dirty = True;
if (HasFeature (featureMultiplePersonalities)) {
if (pers != PersList)
UseFeature (featureMultiplePersonalities);
UpdatePersList();
}
// update IMAP mailboxes with new pers id
if (IsIMAPPers(pers))
IMAPPersIDChanged(pers, (*pers)->mailboxTree);
return(noErr);
}
/**********************************************************************
* SetPersProperty - set a personality's properties via ae's
**********************************************************************/
OSErr SetPersProperty(AEDescPtr token,AEDescPtr descP)
{
short err=noErr;
Str255 str;
PersSpecifier persSpec;
AEGetDescData(token,&persSpec,sizeof(persSpec));
switch (persSpec.property.propertyId)
{
case pName:
if (HasFeature (featureMultiplePersonalities) && persSpec.pers!=PersList)
{
UseFeature (featureMultiplePersonalities);
GetAEPStr(str,descP);
PersSetName(persSpec.pers,str);
NotifyPersonalitiesWin();
}
else
return(errAENotModifiable);
break;
case formUniqueID:
return(errAENotModifiable);
break;
default:
err = errAENoSuchObject;
break;
}
return(err);
}
/**********************************************************************
*
**********************************************************************/
OSErr GetPersProperty(AEDescPtr token,AppleEvent *reply,long refCon)
{
#pragma unused(refCon)
OSErr err;
Str255 s;
PersSpecifier persSpec;
AEGetDescData(token,&persSpec,sizeof(persSpec));
switch (persSpec.property.propertyId)
{
case pName:
err = AEPutPStr(reply,keyAEResult,PCopy(s,(*persSpec.pers)->name));
break;
case formUniqueID:
err = AEPutLong(reply,keyAEResult,(*persSpec.pers)->persId);
break;
default:
err = errAENoSuchObject;
break;
}
return(err);
}
/**********************************************************************
* AECreatePersonality - create a personality
**********************************************************************/
OSErr AECreatePersonality(DescType theClass,AEDescPtr inContainer,AppleEvent *event, AppleEvent *reply)
{
OSErr err;
PersHandle pers;
long n;
AEDesc obj;
if (!HasFeature (featureMultiplePersonalities))
return (paramErr);
UseFeature (featureMultiplePersonalities);
NullADList(&obj,nil);
n = PersCount()+1;
if (pers = PersNew())
{
err = AEPersObj(pers,&obj);
if (!err) err = AEPutParamDesc(reply,keyAEResult,&obj);
if (!err) NotifyPersonalitiesWin();
}
else err = MemError() ? MemError() : errAEEventNotHandled;
DisposeADList(&obj,nil);
return(err);
}
/************************************************************************
* AEPersObj - build an object for a personality
************************************************************************/
OSErr AEPersObj(PersHandle pers,AEDescPtr obj)
{
OSErr err;
long n;
AEDesc desc, root;
if (!HasFeature (featureMultiplePersonalities))
return (paramErr);
if (pers != PersList)
UseFeature (featureMultiplePersonalities);
NullADList(&desc,obj,&root,nil);
n = Pers2Index(pers);
if (!(err = AECreateDesc(typeChar,(*pers)->name+1,*(*pers)->name,&desc)))
{
err = CreateObjSpecifier(cEuPersonality,&root,formName,&desc,False,obj);
}
DisposeADList(&desc,&root,nil);
if (err) DisposeADList(obj,nil);
return(err);
}
/************************************************************************
* AESetPers - set a personality to an object
************************************************************************/
OSErr AESetPers(TOCHandle tocH,short sumNum,AEDescPtr descP)
{
AEDesc token;
OSErr err;
PersHandle pers;
if (!HasFeature (featureMultiplePersonalities))
return (paramErr);
err = AEResolve(descP,kAEIDoMinimum,&token);
if (err) return(err);
if (token.descriptorType!=cEuPersonality) return(errAEWrongDataType);
AEGetDescData(&token,&pers,sizeof(pers));
if (pers != PersList)
UseFeature (featureMultiplePersonalities);
return SetPers(tocH,sumNum,pers,True);
}
/**********************************************************************
* PersCount - how many personalities?
**********************************************************************/
long PersCount(void)
{
long n=0;
PersHandle pers;
for (pers=PersList;pers;pers=(*pers)->next) n++;
return(n);
}
/**********************************************************************
* DisposePersonalities - kill the current personality list
**********************************************************************/
void DisposePersonalities(void)
{
PersHandle pers;
while (pers=PersList)
{
LL_Remove(PersList,pers,(PersHandle));
ZapHandle(pers);
}
CurPers = PersList = nil;
}
/**********************************************************************
* SetPers - set the personality of a message
**********************************************************************/
OSErr SetPers(TOCHandle tocH,short sumNum,PersHandle pers,Boolean stationery)
{
WindowPtr messWinWP;
MessHandle messH = (*tocH)->sums[sumNum].messH;
Boolean opened = messH==nil;
Str255 addr;
OSErr err = noErr;
uLong sigId;
ControlHandle cntl;
Boolean redirected = ((*tocH)->sums[sumNum].opts & OPT_REDIRECTED)!=0;
if ((*tocH)->sums[sumNum].persId==(*pers)->persId) return(noErr); // nothing to do
if (pers!=PersList)
UseFeature (featureMultiplePersonalities);
(*tocH)->sums[sumNum].persId = (*pers)->persId;
TOCSetDirty(tocH,true);
SetBGColorsByPers(messH);
#ifdef THREADING_ON
if ((*tocH)->which==OUT && ((*tocH)->sums[sumNum].state!=SENT && (*tocH)->sums[sumNum].state!=BUSY_SENDING))
#else
if ((*tocH)->which==OUT && (*tocH)->sums[sumNum].state!=SENT)
#endif
{
if (stationery && !redirected) // if stationery not allowed, don't copy sig
{
PushPers(pers);
sigId = SigValidate(GetPrefLong(PREF_SIGFILE));
PopPers();
SetSig(tocH,sumNum,sigId);
}
if (opened)
{
(void) OpenComp(tocH,sumNum,nil,nil,False,False);
messH = (*tocH)->sums[sumNum].messH;
}
if (!messH) return(errAENoSuchObject);
messWinWP = GetMyWindowWindowPtr((*messH)->win);
PushPers(pers);
GetReturnAddr(addr,True);
PeteCalcOff(TheBody);
if (redirected)
err = RedirectAnnotation(messH);
else
err = SetMessText(messH,FROM_HEAD,addr+1,*addr);
if (stationery) ApplyDefaultStationery((*messH)->win,False,False);
PeteKillUndo(TheBody);
PopPers();
if (opened)
{
err = !SaveComp((*messH)->win) ? err : True;
CloseMyWindow(messWinWP);
}
else
{
if (HasFeature (featureMultiplePersonalities)) {
CheckNone(GetMHandle(PERS_HIER_MENU));
if (cntl=FindControlByRefCon((*messH)->win,'pers'))
{
short item = pers==PersList ? 1 : Pers2Index(pers)+2;
if (item!=GetControlValue(cntl))
{
SetControlMaximum(cntl,PersCount()+1);
SetControlValue(cntl,item);
}
}
}
}
}
return(err);
}
/**********************************************************************
* SetBGColorsByPers - set the bg colors by the personality of a message
**********************************************************************/
void SetBGColorsByPers(MessHandle messH)
{
// change the bg color?
if (messH)
{
PETEHandle pte;
RGBColor color;
PushPers(PERS_FORCE(MESS_TO_PERS(messH)));
GetRColor(&color,BACK_COLOR);
PopPers();
if (!SAME_COLOR(color,(*messH)->win->backColor))
{
Rect r = {-REAL_BIG/2,-REAL_BIG/2,REAL_BIG/2,REAL_BIG/2};
(*messH)->win->backColor = color;
InvalWindowRect(GetMyWindowWindowPtr((*messH)->win),&r);
for (pte=(*messH)->win->pteList;pte;pte=PeteNext(pte))
PETESetDefaultBGColor(PETE,pte,&color);
}
}
}
/**********************************************************************
* PersCheckTicks - find the earliest check interval
**********************************************************************/
uLong PersCheckTicks(void)
{
PersHandle pers;
uLong ticks=0;
for (pers=PersList;pers;pers=(*pers)->next)
if ((*pers)->autoCheck)
{
if (!ticks) ticks = (*pers)->checkTicks+(*pers)->ivalTicks;
else ticks = MIN(ticks,(*pers)->checkTicks+(*pers)->ivalTicks);
}
return(ticks);
}
/**********************************************************************
* PersSkipNextCheck - skip the next check.
**********************************************************************/
void PersSkipNextCheck(void)
{
PersHandle pers;
uLong ticks=0;
// Reset all mail checks that were about to happen
for (pers=PersList;pers;pers=(*pers)->next)
if ((*pers)->autoCheck)
{
// if this check was about to happen, pretend it did.
if ((*pers)->checkTicks+(*pers)->ivalTicks <= TickCount()+45*60)
(*pers)->checkTicks = TickCount();
}
}
/**********************************************************************
* PersSetAutoCheck - set the autocheck flag
**********************************************************************/
void PersSetAutoCheck(void)
{
long ival;
Str255 s;
Boolean is;
PushPers(CurPers);
for (CurPers=PersList;CurPers;CurPers=(*CurPers)->next)
{
if (PrefIsSet(PREF_AUTO_CHECK) && (ival=GetPrefLong(PREF_INTERVAL)) && *GetPOPPref(s))
{
(*CurPers)->autoCheck = True;
(*CurPers)->ivalTicks = TICKS2MINS * ival;
}
else
{
(*CurPers)->autoCheck = False;
(*CurPers)->ivalTicks = 0;
}
is = *GetPOPPref(s) && s[1]=='!';
(*CurPers)->uupcIn = is?1:0;
is = *GetPref(s,PREF_SMTP) && s[1]=='!';
(*CurPers)->uupcOut = is?1:0;
}
PopPers();
}
/**********************************************************************
* Pers2Index - return the index of a personality
**********************************************************************/
short Pers2Index(PersHandle goalPers)
{
short index=0;
PersHandle pers;
if (!goalPers) return(-1);
for (pers=PersList;pers && pers!=goalPers;pers=(*pers)->next) index++;
return(pers?index:-1);
}
/**********************************************************************
* Index2Pers - return the indexed personality
**********************************************************************/
PersHandle Index2Pers(short n)
{
PersHandle pers;
for (pers=PersList;n-- && pers;pers=(*pers)->next);
return(pers);
}
/************************************************************************
* CheckPers - put a check next to the current message's personality
************************************************************************/
void CheckPers(MyWindowPtr win,Boolean all)
{
WindowPtr winWP = GetMyWindowWindowPtr(win);
MenuHandle mh;
MessHandle messH;
TOCHandle tocH;
short n;
Boolean out;
short kind;
PersHandle pers, messPers;
//No personalities menu in Light
if (!HasFeature (featureMultiplePersonalities))
return;
mh = GetMHandle(PERS_HIER_MENU);
messH = win?(MessHandle) GetMyWindowPrivateData(win):nil;
tocH = win?(TOCHandle) GetMyWindowPrivateData(win):nil;
out=False;
kind = winWP ? GetWindowKind(winWP) : 0;
/*
* uncheck old one
*/
CheckNone(mh);
EnableItem(mh,0);
if (all) return;
if (IsMyWindow(winWP))
{
/*
* set n to current state
*/
n = 0;
if (kind==MESS_WIN || kind==COMP_WIN)
{
messPers = PERS_FORCE(MESS_TO_PERS(messH));
out = kind==COMP_WIN;
}
else if ((kind==MBOX_WIN || kind==CBOX_WIN) && win->hasSelection)
{
messPers = PERS_FORCE(FindPersById((*tocH)->sums[FirstMsgSelected(tocH)].persId));
out = kind==CBOX_WIN;
}
else
{
DisableItem(mh,0);
return;
}
/*
* check the appropriate item
*/
if (messPers==PersList) n = 1;
else
{
n = 3;
for (pers=(*PersList)->next;pers;pers=(*pers)->next)
if (pers==messPers) break;
else n++;
}
SetItemMark(mh,n,checkMark);
}
CalcMenuSize(mh);
}
/************************************************************************
* UpdatePersList - sort personalities and rebuild personalities menu
************************************************************************/
static void UpdatePersList(void)
{
PersHandle pers,**hPersList;
short count;
//No personalities menu in Light
if (!HasFeature (featureMultiplePersonalities))
return;
count = PersCount();
if (count <= 2)
; // Not enough items to sort
else if (hPersList=NuHandleClear((count+2)*sizeof(PersHandle)))
{
PersHandle *pPersList;
short idx;
pPersList=LDRef(hPersList);
for (pers=PersList;pers;pers=(*pers)->next)
*pPersList++ = pers;
*pPersList = nil; // Used later for rebuilding linked list
QuickSort((void *)*hPersList,sizeof(PersHandle),1,count-1,(void*)PersCompare,(void*)PersSwap);
// Rebuild personalities list
pPersList=*hPersList;
for(idx=0;idx<count;idx++)
(*pPersList[idx])->next = pPersList[idx+1];
}
BuildPersMenu();
}
/************************************************************************
* PersCompare - compare two personality names
************************************************************************/
static int PersCompare(PersHandle *p1, PersHandle *p2)
{
if (*p1==0) return 1;
if (*p2==0) return -1;
return(StringComp((**p1)->name,(**p2)->name));
}
/************************************************************************
* PersSwap - swap two personality handles
************************************************************************/
static void PersSwap(PersHandle *n1, PersHandle *n2)
{
PersHandle temp = *n2;
*n2 = *n1;
*n1 = temp;
}
enum
{
kOKItem = 1,
kCancelItem,
kListItem,
kIconItem,
kPromptItem
};
/************************************************************************
* PersChoose - choose a personality from a dialog list
************************************************************************/
PersHandle PersChoose(StringPtr prompt)
{
MyWindowPtr dlogWin;
DialogPtr dlog;
short res;
extern ModalFilterUPP DlgFilterUPP;
PersHandle pers,result;
short type;
Rect r;
ControlHandle cntl;
ListHandle list;
Point c;
Str63 name;
// Dominant personality only in Light
if (!HasFeature (featureMultiplePersonalities))
return (PersList);
if (PersCount()==1) return PersList; // Only 1 personality, return it
UseFeature (featureMultiplePersonalities);
SetDialogFont (SmallSysFontID());
dlogWin = GetNewMyDialog(CHOOSE_PERSONALITY_DLOG,nil,nil,InFront);
SetDialogFont(0);
dlog = GetMyWindowDialogPtr(dlogWin);
if (!dlog) { WarnUser(MEM_ERR,ResError()); return nil; }
SetPort_(GetMyWindowCGrafPtr(dlogWin));
ConfigFontSetup(dlogWin);
if (prompt)
// Set prompt
SetDIText(dlog,kPromptItem,prompt);
// add personality list
GetDialogItem(dlog,kListItem,&type,(void*)&cntl,&r);
if (list = LCGetList(cntl))
{
(*list)->selFlags = lOnlyOne;
// The following may not have been set up appropriately on LNew
c.h = r.right - GROW_SIZE - 1;
c.v = dlogWin->vPitch + 2;
LCellSize(c, list);
(*list)->indent.v = dlogWin->vPitch-2;
c.h = c.v = 0;
LAddRow(PersCount(),0,list);
for (pers=PersList;pers;pers=(*pers)->next)
{
PSCopy(name,(*pers)->name);
LSetCell(name+1,*name,c,list);
c.v++;
}
}
ReplaceAllControls(dlog);
// put up the alert
StartMovableModal(dlog);
ShowWindow(GetDialogWindow(dlog));
SetMyCursor(arrowCursor);
do
{
MovableModalDialog(dlog,DlgFilterUPP,&res);
}
while (res>kCancelItem);
result = (res!=kCancelItem && FirstSelected(&c,list)) ? Index2Pers(c.v) : nil;
// close
EndMovableModal(dlog);
DisposeDialog_(dlog);
return result;
}