/* 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 "personalitieswin.h"

#define FILE_NUM 87
/* Copyright (c) 1996 by QUALCOMM Incorporated */

#pragma segment PersonWin

// Personality Window controls
enum
{
	kctlNew=0,
	kctlRemove,
	kctlCheck,
	kctlEdit
};

typedef struct
{
	ViewList list;
	MyWindowPtr win;
	ControlHandle ctlNew,ctlRemove,ctlCheck,ctlEdit;
	Boolean	inited;
	PersHandle	newPers;	//	New personality being renamed
} WinData;
static WinData gWin;
static Boolean	gMyCheck;

/************************************************************************
 * prototypes
 ************************************************************************/
static void DoDidResize(MyWindowPtr win, Rect *oldContR);
static void DoZoomSize(MyWindowPtr win,Rect *zoom);
static void DoUpdate(MyWindowPtr win);
static Boolean DoClose(MyWindowPtr win);
static void DoClick(MyWindowPtr win,EventRecord *event);
static void DoCursor(Point mouse);
static void DoActivate(MyWindowPtr win);
static Boolean DoKey(MyWindowPtr win, EventRecord *event);
static OSErr DoDragHandler(MyWindowPtr win,DragTrackingMessage which,DragReference drag);
static void DoShowHelp(MyWindowPtr win,Point mouse);
static Boolean DoMenuSelect(MyWindowPtr win, int menu, int item, short modifiers);
static long ViewListCallBack(ViewListPtr pView, VLCallbackMessage message, long data);
static Boolean GetListData(VLNodeInfo *data,short selectedItem);
static void SetControls(void);
static void DeletePersonality(void);
static void NewPersonality(void);
static void RenamePersonality(StringPtr newName);
static void ReplyWithPers(MessHandle messH,PersHandle pers,short modifiers);
static void DoGrow(MyWindowPtr win,Point *newSize);
static void ProcessPersPassword(Boolean change);
static void PersIdle(MyWindowPtr win);
static Boolean PersFind(MyWindowPtr win,PStr what);
static void OpenSelectedPers(void);
extern void CopyExtraSigs(MenuHandle mh);

typedef enum {
	kOK = 1,
	kCancel,
	kPersName,
	kPopAccount,
	kRealName,
	kReturnAddress,
	kAutoCheck,
	kCheckInverval,
	kCheckManual,
	kLeaveMail,
	kPasswords,
	kKerberos,
	kAPOP,
	kDomain2Add,
	kSMTPServer,
	kStationeryMenu,
	kSignatureMenu,
	kSendManual
}	EditPersDialogEnum;

/************************************************************************
 * OpenPersonalitiesWin - open the stationery window
 ************************************************************************/
void OpenPersonalitiesWin(void)
{
	WindowPtr	gWinWinWP;
	
	if (!HasFeature (featureMultiplePersonalities))
		return;
	
	if (SelectOpenWazoo(PERS_WIN)) return;	//	Already opened in a wazoo

	if (!gWin.inited)
	{
		short err=0;
		Rect r;
		
		if (!(gWin.win=GetNewMyWindow(PERSONALITIES_WIND,nil,nil,BehindModal,false,false,PERS_WIN)))
			{err=MemError(); goto fail;}
		gWinWinWP = GetMyWindowWindowPtr (gWin.win);
		SetWinMinSize(gWin.win,-1,-1);
		SetPort_(GetWindowPort(gWinWinWP));
		ConfigFontSetup(gWin.win);	
		MySetThemeWindowBackground(gWin.win,kThemeListViewBackgroundBrush,False);

		/*
		 * list
		 */
		SetRect(&r,0,0,20,20);
		if (LVNew(&gWin.list,gWin.win,&r,1,ViewListCallBack,kPersonalityDragType))
			{err=MemError(); goto fail;}
		
		// controls
		if (!(gWin.ctlNew = NewIconButton(PERS_NEW_CNTL,gWinWinWP)) ||
			!(gWin.ctlRemove = NewIconButton(PERS_REMOVE_CNTL,gWinWinWP)) ||
			!(gWin.ctlCheck = NewIconButton(PERS_CHECK_CNTL,gWinWinWP)) ||
			!(gWin.ctlEdit = NewIconButton(PERS_EDIT_CNTL,gWinWinWP)))
				goto fail;
			
		gWin.win->didResize = DoDidResize;
		gWin.win->close = DoClose;
		gWin.win->update = DoUpdate;
		gWin.win->position = PositionPrefsTitle;
		gWin.win->click = DoClick;
		gWin.win->bgClick = DoClick;
		gWin.win->dontControl = true;
		gWin.win->cursor = DoCursor;
		gWin.win->activate = DoActivate;
		gWin.win->help = DoShowHelp;
		gWin.win->menu = DoMenuSelect;
		gWin.win->key = DoKey;
		gWin.win->app1 = DoKey;
		gWin.win->drag = DoDragHandler;
		gWin.win->zoomSize = DoZoomSize;
		gWin.win->grow = DoGrow;
		gWin.win->idle = PersIdle;
		gWin.win->find = PersFind;
		gWin.win->showsSponsorAd = true;
		ShowMyWindow(gWinWinWP);
		MyWindowDidResize(gWin.win,&gWin.win->contR);
		gWin.inited = true;
		return;
		
		fail:
			if (gWin.win) CloseMyWindow(GetMyWindowWindowPtr (gWin.win));
			if (err) WarnUser(COULDNT_WIN,err);
			return;
	}
	UserSelectWindow(GetMyWindowWindowPtr(gWin.win));
}

/************************************************************************
 * DoDidResize - resize the window
 ************************************************************************/
static void DoDidResize(MyWindowPtr win, Rect *oldContR)
{
#define kListInset 10 
#pragma unused(oldContR)
	ControlHandle	ctlList[4];
	Rect r;
	short	htAdjustment;
			
	//	buttons
	ctlList[0] = gWin.ctlNew;
	ctlList[1] = gWin.ctlRemove;
	ctlList[2] = gWin.ctlCheck;
	ctlList[3] = gWin.ctlEdit;
	PositionBevelButtons(win,4,ctlList,kListInset,gWin.win->contR.bottom-INSET-kHtCtl,kHtCtl,RectWi(win->contR));

	// list
	SetRect(&r,kListInset,win->topMargin+kListInset,gWin.win->contR.right-kListInset,gWin.win->contR.bottom - 2*INSET - kHtCtl);
	if (gWin.win->sponsorAdExists && r.bottom >= gWin.win->sponsorAdRect.top - kSponsorBorderMargin)
		r.bottom = gWin.win->sponsorAdRect.top - kSponsorBorderMargin;
	LVSize(&gWin.list,&r,&htAdjustment);

	//	enable/disble controls
	SetControls();
	
	// redraw
	InvalContent(win);
}

/************************************************************************
 * SetControls - enable or disable the controls, based on current situation
 ************************************************************************/
static void SetControls(void)
{
	VLNodeInfo	info;
	short		count = LVCountSelection(&gWin.list);
	Boolean fSelect = count!=0;
	
	
	gWin.win->hasSelection = fSelect;

	SetGreyControl(gWin.ctlEdit,count!=1);	
	SetGreyControl(gWin.ctlCheck,!fSelect || CheckThreadRunning);	

	if (fSelect)
	{
		GetListData(&info,1);
		if (info.rowNum == 1)
			fSelect = false;	//	Can't remove the dominant personality
	}

	SetGreyControl(gWin.ctlRemove,!fSelect);	
}

/************************************************************************
 * DoZoomSize - zoom to only the maximum size of list
 ************************************************************************/
static void DoZoomSize(MyWindowPtr win,Rect *zoom)
{
	short zoomHi = zoom->bottom-zoom->top;
	short zoomWi = zoom->right-zoom->left;
	short hi, wi;
	
	LVMaxSize(&gWin.list, &wi, &hi);
	wi += 2*kListInset;
	hi += 2*kListInset + INSET + kHtCtl;

	wi = MIN(wi,zoomWi); wi = MAX(wi,win->minSize.h);
	hi = MIN(hi,zoomHi); hi = MAX(hi,win->minSize.v);
	zoom->right = zoom->left+wi;
	zoom->bottom = zoom->top+hi;
}

/************************************************************************
 * DoGrow - adjust grow size
 ************************************************************************/
static void DoGrow(MyWindowPtr win,Point *newSize)
{
	Rect	r,rWin;
	short	htControl = ControlHi(gWin.ctlNew);
	short	bottomMargin,sponsorMargin;
	
	//	Get list position
	bottomMargin = INSET*2 + htControl;
	if (win->sponsorAdExists)
	{
		WindowPtr	winWP = GetMyWindowWindowPtr (win);
		GetWindowPortBounds(winWP,&rWin);
		sponsorMargin = rWin.bottom - win->sponsorAdRect.top + kSponsorBorderMargin;
		if (sponsorMargin > bottomMargin) bottomMargin  = sponsorMargin;
	}
	SetRect(&r,kListInset,win->topMargin+kListInset,newSize->h-kListInset,newSize->v - bottomMargin);
	LVCalcSize(&gWin.list,&r);
	
	//	Calculate new window height
	newSize->v = r.bottom + bottomMargin;
}

/************************************************************************
 * DoClose - close the window
 ************************************************************************/
static Boolean DoClose(MyWindowPtr win)
{
#pragma unused(win)
	
	if (gWin.inited)
	{
		//	Dispose of list
		LVDispose(&gWin.list);
		gWin.inited = false;
	}
	return(True);
}

/************************************************************************
 * DoUpdate - draw the window
 ************************************************************************/
static void DoUpdate(MyWindowPtr win)
{
	CGrafPtr	winPort = GetMyWindowCGrafPtr (win);
	Rect	r;
	
	r = gWin.list.bounds;
	DrawThemeListBoxFrame(&r,kThemeStateActive);
	LVDraw(&gWin.list,MyGetPortVisibleRegion(winPort), true, false);
}

/************************************************************************
 * DoActivate - activate the window
 ************************************************************************/
static void DoActivate(MyWindowPtr win)
{
#pragma unused(win)
	LVActivate(&gWin.list, gWin.win->isActive);
	gWin.newPers = nil;
	SetControls();
}

/************************************************************************
 * DoKey - key stroke
 ************************************************************************/
static Boolean DoKey(MyWindowPtr win, EventRecord *event)
{
#pragma unused(win)
	short key = (event->message & 0xff);

	if (LVKey(&gWin.list,event))
	{
		SetControls();
		return true;
	}

	return false;
}

/**********************************************************************
 * PersFind - find in the window
 **********************************************************************/
static Boolean PersFind(MyWindowPtr win,PStr what)
{
	return FindListView(win,&gWin.list,what);
}

/************************************************************************
 * DoClick - click in window
 ************************************************************************/
void DoClick(MyWindowPtr win,EventRecord *event)
{
	WindowPtr	winWP = GetMyWindowWindowPtr (win);
	Point pt;
	ControlHandle	hCtl;
	
	SetPort(GetMyWindowCGrafPtr(win));

	if (!LVClick(&gWin.list,event))
	{
		pt = event->where;
		GlobalToLocal(&pt);
		if (!win->isActive)
		{
			SelectWindow_(winWP);
			UpdateMyWindow(winWP);	//	Have to update manually since no events are processed
		}
		
		if (FindControl(pt, winWP, &hCtl))
		{
			if (TrackControl(hCtl,pt,(void *)(-1)))
			{
				long controlId;
	
				if (hCtl == gWin.ctlEdit)
				{
					VLNodeInfo	info;

					GetListData(&info,1);
					DoPersSettings(Index2Pers(info.rowNum-1));
					controlId = kctlEdit;
				}
				else if (hCtl == gWin.ctlNew)
				{
					NewPersonality();
					controlId = kctlNew;
				}
				else if (hCtl == gWin.ctlRemove)
				{
					DeletePersonality();
					controlId = kctlRemove;
				}
				else if (hCtl == gWin.ctlCheck)
				{
					gMyCheck =true;
					XferMail(true,false,true,false,true,0);
					gMyCheck =false;
					controlId = kctlCheck;
				}
				
				AuditHit((event->modifiers&shiftKey)!=0, (event->modifiers&controlKey)!=0, (event->modifiers&optionKey)!=0, (event->modifiers&cmdKey)!=0, false, GetWindowKind(winWP), AUDITCONTROLID(GetWindowKind(winWP),controlId), event->what);
			}
		}
	}
	SetControls();
}

/************************************************************************
 * NotifyPersonalitiesWin - notify the personalities window that we've
 *  been up to no good
 ************************************************************************/
void NotifyPersonalitiesWin(void)
{
	if (!HasFeature (featureMultiplePersonalities))
		return;

	if (gWin.inited) InvalidListView(&gWin.list);	//	Regenerate list	
}

/************************************************************************
 * DoCursor - set the cursor properly for the window
 ************************************************************************/
static void DoCursor(Point mouse)
{
	if (!PeteCursorList(gWin.win->pteList,mouse))
		SetMyCursor(arrowCursor);
}

/************************************************************************
 * DoShowHelp - provide help for the window
 ************************************************************************/
static void DoShowHelp(MyWindowPtr win,Point mouse)
{
	if (PtInRect(mouse,&gWin.list.bounds))
		MyBalloon(&gWin.list.bounds,100,0,PERS_HELP_STRN+1,0,nil);
	else
		ShowControlHelp(mouse,PERS_HELP_STRN+2,gWin.ctlNew,gWin.ctlRemove,gWin.ctlCheck,gWin.ctlEdit,nil);
}

/************************************************************************
 * GetListData - get data for selected item
 ************************************************************************/
static Boolean GetListData(VLNodeInfo *data,short selectedItem)
{
	return LVGetItem(&gWin.list,selectedItem,data,true);
}

/************************************************************************
 * DoMenuSelect - menu choice in the window
 ************************************************************************/
static Boolean DoMenuSelect(MyWindowPtr win, int menu, int item, short modifiers)
{
#pragma unused(win,modifiers)
	
	switch (menu)
	{
		case FILE_MENU:
			switch(item)
			{
				case FILE_OPENSEL_ITEM:
					OpenSelectedPers();
					return(True);
					break;
			}
			break;

		case EDIT_MENU:
			switch(item)
			{
				case EDIT_SELECT_ITEM:
					if (LVSelectAll(&gWin.list))
					{
						SetControls();
						return(true);
					}
					break;
					
				case EDIT_COPY_ITEM:
					LVCopy(&gWin.list);
					return true;
			}
			break;
	}
	return(False);
}

/**********************************************************************
 * ReplayWithPers - generate a reply message with indicated personality
 **********************************************************************/
static void ReplyWithPers(MessHandle messH,PersHandle pers,short modifiers)
{
	Boolean all, quote, self;
	MyWindowPtr	newWin;

	if (!HasFeature (featureMultiplePersonalities))
		return;

	UseFeature (featureMultiplePersonalities);
	
	ReplyDefaults(modifiers,&all,&self,&quote);
	if (newWin = DoReplyMessage((*messH)->win,all,self,quote,true,0,false,false,true))
	{
		WindowPtr	newWinWP = GetMyWindowWindowPtr (newWin);
		messH = (MessHandle)GetMyWindowPrivateData(newWin);
		SetPers((*messH)->tocH,(*messH)->sumNum,pers,false);
		ShowMyWindow(newWinWP);
		UpdateMyWindow(newWinWP);							
	}
}

/**********************************************************************
 * DoDragHandler - handle drags
 **********************************************************************/
static OSErr DoDragHandler(MyWindowPtr win,DragTrackingMessage which,DragReference drag)
{	
#pragma unused(win)
	OSErr err = noErr;
	VLNodeInfo targetInfo;
	
	if (!DragIsInteresting(drag,MESS_FLAVOR,TOC_FLAVOR,nil))
		return(dragNotAcceptedErr);	//	Nothing here we want
	
	switch (which)
	{
		case kDragTrackingEnterWindow:
		case kDragTrackingLeaveWindow:
		case kDragTrackingInWindow:
				err = LVDrag(&gWin.list,which,drag);
			break;
		case 0xfff:
			//	Drop
				if (LVDrop(&gWin.list,&targetInfo))
				{
					PersHandle	pers = Index2Pers(targetInfo.rowNum-1);
					UHandle data=nil;
					short	modifiers = DragOrMods(drag);
					
					if (!(err=MyGetDragItemData(drag,1,MESS_FLAVOR,(void*)&data)))
					{
						ReplyWithPers(**(MessHandle**)data, pers, modifiers);
					}
					else if (!(err=MyGetDragItemData(drag,1,TOC_FLAVOR,(void*)&data)))
					{
						short	sumNum;
						TOCHandle tocH;
						
						tocH = **(TOCHandle**)data;
						for (sumNum = 0; sumNum < (*tocH)->count; sumNum++)
						{
							if ((*tocH)->sums[sumNum].selected)
							{
								MyWindowPtr	tempWin;
								
								CycleBalls();
								MiniEvents();
								if (EjectBuckaroo || CommandPeriod) break;

								if (tempWin = GetAMessage(tocH,sumNum,nil,nil,false))
								{
									WindowPtr	tempWinWP = GetMyWindowWindowPtr (tempWin);
									ReplyWithPers((MessHandle)GetMyWindowPrivateData(tempWin), pers, modifiers);										
									if (!IsWindowVisible(tempWinWP))
										CloseMyWindow(tempWinWP);
									else
										NotUsingWindow(tempWinWP);
								}
							}
						}
					}
					
					ZapHandle(data);
					
					return(err);
				}
				else
					return dragNotAcceptedErr;		
				break;
	}
	return err;
}


/************************************************************************
 * ViewListCallBack - callback function for List View
 ************************************************************************/
static long ViewListCallBack(ViewListPtr pView, VLCallbackMessage message, long data)
{
	VLNodeInfo	info,*pInfo;
	OSErr	err = noErr;
	short	i,count;
	PersHandle	pers;
	SendDragDataInfo	*pSendData;

	switch (message)
	{
		case kLVAddNodeItems:
			//	Add personality names to list
			count = PersCount();
			if (count > 1)
				UseFeature (featureMultiplePersonalities);
				
			for (i=1;i<=count;i++)
			{
				Zero(info);
				if (pers = Index2Pers(i-1))
				{
					PCopy(info.name,(*pers)->name);
					info.useLevelZero = true;
					info.iconID = PERSONALITIES_ICON;
				}
				LVAdd(pView, &info);				
			}
			break;
		
		case kLVOpenItem:
			//	New message with personality
			OpenSelectedPers();
			break;
			
		case kLVDeleteItem:
			DeletePersonality();
			break;
		
		case kLVRenameItem:
		{
			Str31 newName;
			SanitizeFN(newName,(StringPtr)data,MAC_FN_BAD,MAC_FN_REP,false);
			RenamePersonality(newName);
			break;
		}
		case kLVQueryItem:
			pInfo = (	VLNodeInfo *)data;
			switch (pInfo->query)
			{
				case kQuerySelect:
				case kQueryDrag:
				case kQueryDrop:
				case kQueryDCOpens:
					return true;
				case kQueryRename:
					return pInfo->rowNum > 1;
			}
			break;

		case kLVSendDragData:
			pSendData = (SendDragDataInfo *)data;
			pers = Index2Pers(pSendData->info->rowNum-1);
			err = SetDragItemFlavorData(pSendData->drag, pSendData->itemRef, pSendData->flavor,&pers, sizeof(pers), 0L);
	}
	return err;
}

/************************************************************************
 * RenamePersonality - rename the selected personality
 ************************************************************************/
static void RenamePersonality(StringPtr newName)
{
	VLNodeInfo	info;
	PersHandle	pers;
	Str255 scratch;

	if (!*newName) {WarnUser(PERS_MUST_HAVE_NAME,0);return;}
	
	GetListData(&info,1);
	if ((pers = Index2Pers(info.rowNum-1)) && (!EqualString(newName,PCopy(scratch,(*pers)->name),true,true)))
	{
	  if (gWin.newPers == pers || 
	  	Aprintf(YES_CANCEL_ALRT,Stop,PERS_RENAME,scratch)==1)
	  {
#ifdef IMAP
			if (IsIMAPPers(pers))
				if (!RenameIMAPPers(pers,newName))
				{
					if (gWin.newPers == pers) DoPersSettings(pers);
					goto Done;
				}
#endif
			if (!PersSetName(pers,newName))
			{
				InvalidListView(&gWin.list);	//	Regenerate list
				if (gWin.newPers == pers) DoPersSettings(pers);
			}
		}
 Done:
		gWin.newPers = nil;
	}
}

/************************************************************************
 * DeletePersonality - delete the selected personality
 ************************************************************************/
static void DeletePersonality(void)
{
	short	i;
	VLNodeInfo	info;
	Str255 scratch;
	PersHandle	pers;
	Boolean	fDeleted = false;
	
	for (i=1;i<=LVCountSelection(&gWin.list);i++)
	{
		GetListData(&info,i);
		if (info.rowNum == 1)
			continue;	//	Can't delete dominant personality
		if (pers = FindPersByName(info.name))
		{
#ifdef IMAP
			if (IsIMAPPers(pers))
			{
				if (ComposeStdAlert(Stop,IMAP_DELETE_CACHE,PCopy(scratch,(*pers)->name))==1)
				{
					DeleteIMAPPers(pers, false);
					PersDelete(pers);
					fDeleted = true;
				}
				else break;
			}
			else
			{
#endif
				if (Aprintf(YES_CANCEL_ALRT,Stop,PERS_DELETE,PCopy(scratch,(*pers)->name))==1)
				{
					PersDelete(pers);
					fDeleted = true;
				}
				else break;
			}
		}
	}
	if (fDeleted)
	{
		InvalidListView(&gWin.list);	//	Regenerate list
		UpdateMyWindow(GetMyWindowWindowPtr(gWin.win));
	}
}

/************************************************************************
 * NewPersonality - new personality
 ************************************************************************/
static void NewPersonality(void)
{
	PersHandle	pers;

	if (HasFeature(featureMultiplePersonalities) && (pers=PersNew()))
	{
		UseFeature (featureMultiplePersonalities);
		InvalidListView(&gWin.list);	//	Regenerate list
		gWin.newPers = pers;
		LVRename(&gWin.list,0,(*pers)->name,false,false);	//	Allow user to rename the personality
	}
}

/************************************************************************
 * SelectXferMailPers - select which personalities to check mail/send queued messages
 ************************************************************************/
Boolean SelectXferMailPers(Boolean check, Boolean send, Boolean manual)
{
	//	Specify personalities to check/send if Personalities window is active
	//	and there are one or more personalities selected
	if (gMyCheck && check && manual && gWin.inited)
	{
		short	i;
		PersHandle	pers;
		
		//	Mark the personalities that need to be checked/sent
		for (i=1,pers=PersList;pers;pers=(*pers)->next,i++)
		{
			Boolean	selected = LVIsSelected(&gWin.list,i);
			PersPtr	pPers = *pers;
			
			pPers->doMeNow = check || send;
			pPers->checkMeNow = selected && check;
			pPers->sendMeNow = selected && send;
			pPers->checked = false;
		}		
		return true;
	}
	return false;
}

#if 0
/************************************************************************
 * EditPersonality - edit the selected personality
 ************************************************************************/
static void EditPersonality(void)
{
	MyWindowPtr	dlogWin;
	DialogPtr dlog;
	WindowPtr	dlogWP;
	short res;
	extern ModalFilterUPP DlgFilterUPP;
	Str255 scratch;
	long	sigId;
	VLNodeInfo	info;
	PersHandle	pers = nil;
	ControlHandle	hSigCntl,hStnyCntl;
	MenuHandle	hSigMenu,hStnyMenu,hTempMenu;
	short	value,count,i;
	Style style;
	typedef struct
	{
		short	item,pref;
	} DlgPrefData;
	static DlgPrefData	DlgPrefTable[] = 
	{
		//	Negative item #'s for check boxes
		//	Negative pref #'s for opposite values
		kPopAccount,PREF_POP,
		kRealName,PREF_REALNAME,
		kReturnAddress,PREF_RETURN,
		-kAutoCheck,PREF_AUTO_CHECK,
		kCheckInverval,PREF_INTERVAL,
		-kCheckManual,-PREF_JUST_SAY_NO,
		-kLeaveMail,PREF_LMOS,
		-kPasswords,-PREF_DONT_PASS,
		-kKerberos,PREF_KERBEROS,
		-kAPOP,PREF_APOP,
		kDomain2Add,PREF_AUTOQUAL,
		kSMTPServer,PREF_SMTP,
		-kSendManual,-PREF_PERS_NO_SEND,
		0,0
	};
	DlgPrefData	*pDlgPref;
	PersHandle oldCur = CurPers;


	GetListData(&info,1);
	pers = Index2Pers(info.rowNum-1);
	if (!pers) return;	//	Shouldn't happen

	SetDAFont(SmallSysFont());
	dlogWin = GetNewMyDialog(EDIT_PERSONALITY_DLOG,nil,nil,InFront);
	SetDAFont(0);
	if (!dlog) {(WarnUser(MEM_ERR,ResError())); return;}
	dlog = GetMyWindowDialogPtr (dlogWin);
	dlogWP = GetDialogWindow (dlog);
	SetPort_(GetWindowPort(dlogWP));
	ConfigFontSetup(dlogWin);	

	// fix the dialog controls
	ReplaceAllControls(dlog);
	
	SetDIText(dlog,kPersName,(*pers)->name);
	
	//	Set dialog items from preferences
	CurPers = pers;	//	Use prefs for indicated personality
	for(pDlgPref=DlgPrefTable;pDlgPref->item;pDlgPref++)
	{
		if (pDlgPref->item < 0)
			//	Checkbox item
			SetDItemState(dlog,-pDlgPref->item,pDlgPref->pref<0 ? !PrefIsSet(-pDlgPref->pref) : PrefIsSet(pDlgPref->pref));
		else
			//	Text item
			SetDIText(dlog,pDlgPref->item,GetPref(scratch,pDlgPref->pref));
	}
	
	//	Setup signature menu
	hSigCntl = GetDItemCtl(dlog,kSignatureMenu);
	hSigMenu = (MenuHandle)GetControlPopupMenuHandle(hSigCntl);
	CopyExtraSigs(hSigMenu);
	SetCtlMax(hSigCntl,CountMItems(hSigMenu));
	sigId = SigValidate(GetPrefLong(PREF_SIGFILE));
	switch (sigId)
	{
		case SIG_NONE: value = sigmNone; break;
		case SIG_STANDARD: value = sigmStandard; break;
		case SIG_ALTERNATE:	value = sigmAlternate; break;
		default:
			for (value=CountMItems(hSigMenu);value>sigmAlternate;value--)
			{
				MyGetItem(hSigMenu,value,scratch);
				MyLowerStr(scratch);
				if (Hash(scratch)==sigId) break;
			}
			break;
	}
	SetCtlValue(hSigCntl,value);
			
	//	Setup stationery menu
	hStnyCntl = GetDItemCtl(dlog,kStationeryMenu);
	GetPref(scratch,STATIONERY);
	hStnyMenu = (MenuHandle)GetControlPopupMenuHandle(hStnyCntl);
	hTempMenu = GetMHandle(REPLY_WITH_HIER_MENU);
	count = CountMItems(hTempMenu);
	SetCtlMax(hStnyCntl,count+2);
	GetItemStyle(hTempMenu,1,&style);
	value = 1;
	if (count>1 || !style)
		for (i=1;i<=count;i++)
		{
			MyGetItem(hTempMenu,i,scratch);
			MyAppendMenu(hStnyMenu,scratch);
			if (EqualStrRes(scratch,STATIONERY)) value = i+2;
		}
	SetCtlValue(hStnyCntl,value);
	
	CurPers = oldCur;	//	Restore the current personality

	// put up the alert
	StartMovableModal(dlog);
	ShowWindow(dlogWP);
	SetMyCursor(arrowCursor);
	
	do
	{
		MovableModalDialog(dlog,DlgFilterUPP,&res);
		if (!DialogRadioButtons(dlogWin,res))
			DialogCheckbox(dlogWin,res);
		if (res>kCancel) (dlogWin)->isDirty = true;
	}
	while (res>kCancel);

	if (dlogWin->isDirty && res==kOK)
	{
		//	Save settings
		CurPers = pers;	//	Use prefs for indicated personality
		for(pDlgPref=DlgPrefTable;pDlgPref->item;pDlgPref++)
		{
			short	value, pref;
			if (pDlgPref->item < 0)
			{
				//	Checkbox item
				value = GetDItemState(dlog,-pDlgPref->item);
				pref = pDlgPref->pref;
				if (pref<0)
				{
					pref = -pref;
					value = !value;
				}
				SetPref(pref,value?YesStr:NoStr);
			}
			else
			{
				//	Text item
				GetDIText(dlog,pDlgPref->item,scratch);
				SetPref(pDlgPref->pref,scratch);
			}
		}
		
		//	Save signature
		value = GetCtlValue(hSigCntl);
		switch (value)
		{
			case sigmNone: sigId = SIG_NONE; break;
			case sigmStandard: sigId = SIG_STANDARD; break;
			case sigmAlternate: sigId = SIG_ALTERNATE; break;
			default:
				MyGetItem(hSigMenu,value,scratch);
				MyLowerStr(scratch);
				sigId = Hash(scratch);
				break;
		}
		NumToString(sigId,scratch);
		SetPref(PREF_SIGFILE,scratch);

		//	Save stationery
		value = GetCtlValue(hStnyCntl);
		if (value==1)
			PCopy(scratch,NoStr);
		else
			GetItem(hStnyMenu,value,scratch);
		SetPref(STATIONERY,scratch);
		
		CurPers = oldCur;	//	Restore the current personality
	}

	//	close
	EndMovableModal(dlog);
	DisposeDialog_(dlog);
	CurPers = oldCur;
}
#endif	//	EditPersonality

/************************************************************************
 * ProcessPassword - change or forget password for selected personalities
 ************************************************************************/
static void ProcessPersPassword(Boolean change)
{
	short	i;
	PersHandle	pers;
	PersHandle oldCur = CurPers;
	
	if (!HasFeature (featureMultiplePersonalities))
		return;

	for (i=1,pers=PersList;pers;pers=(*pers)->next,i++)
	{
		if (LVIsSelected(&gWin.list,i))
		{
			CurPers = pers;
			if (change)
				ChangePassword();
			else
				InvalidatePasswords(false,false,false);
		}
	}
	CurPers = oldCur;
}

/************************************************************************
 * ChangePersPassword - change password for selected personalities
 ************************************************************************/
void ChangePersPassword(void)
{
	ProcessPersPassword(true);
}

/************************************************************************
 * ForgetPersPassword - forget password for selected personalities 
 ************************************************************************/
void ForgetPersPassword(void)
{
	ProcessPersPassword(false);
}

#ifdef	IMAP
/************************************************************************
 * EmptyIMAPPersTrash - empty trash for selected IMAP personalities 
 ************************************************************************/
void EmptyIMAPPersTrash(void)
{
	short	i;
	PersHandle	pers;
	Boolean warnMe = !PrefIsSet(PREF_NO_TRASH_WARN);

	PushPers(nil);
	
	for (i=1,pers=PersList;pers;pers=(*pers)->next,i++)
	{
		if (LVIsSelected(&gWin.list,i))
		{
			CurPers = pers;
			if (PrefIsSet(PREF_IS_IMAP)) 
			{
				// Warn the user once what's about to happen
				if (warnMe)
				{
					warnMe = false;
					if (!Mom(EMPTY_BUTTON,0,PREF_NO_TRASH_WARN,IMAP_EMPTY_TRASH_WARN)) break;		
				}
				
				IMAPEmptyPersTrash();
			}
		}
	}
	
	PopPers();
}
#endif

/************************************************************************
 * DoWeUseSelectedPersonalities - do we use selected personalities? 
 ************************************************************************/
//	Use only if front window is Personalities window and items are selected
Boolean DoWeUseSelectedPersonalities(void)
{
	WindowPtr	theWindow;
	
	if (!HasFeature (featureMultiplePersonalities))
		return (false);

	return (theWindow=FrontWindow_()) && 
		GetWindowKind(theWindow) == PERS_WIN &&
		LVCountSelection(&gWin.list);
}

/************************************************************************
 * DoWeUseSelectedIMAPPersonalities - do we use selected personalities? 
 ************************************************************************/
Boolean DoWeUseSelectedIMAPPersonalities(void)
{
	Boolean imapSelected = false;
	WindowPtr	theWindow;
	short	i;
	VLNodeInfo	info;
	if (!HasFeature (featureMultiplePersonalities))
		return (false);

	if ((theWindow=FrontWindow_()) && (GetWindowKind(theWindow) == PERS_WIN))
	{
		for (i=1;(i<=LVCountSelection(&gWin.list)) && !imapSelected;i++)
		{
			GetListData(&info,i);
			imapSelected = IsIMAPPers(Index2Pers(info.rowNum-1));
		}
	}
	
	return (imapSelected);
}

/************************************************************************
 * PersIdle - make sure check personality button is in sync with background checking
 ************************************************************************/
static void PersIdle(MyWindowPtr win)
{
	static Boolean	lastCheck;
	
	if (gWin.inited && CheckThreadRunning != lastCheck)
	{
		SetControls();
		lastCheck = CheckThreadRunning;
	}
}

/************************************************************************
 * OpenSelectedPers - make new message the selected personalities
 ************************************************************************/
static void OpenSelectedPers(void)
{
	short	i;
	VLNodeInfo	info;
	
	for (i=1;i<=LVCountSelection(&gWin.list);i++)
	{
		MyWindowPtr win;
		
		GetListData(&info,i);
		
		if (win = DoComposeNew(nil))
		{
			MessHandle messH = (MessHandle)GetMyWindowPrivateData(win);
			
			if (info.rowNum == 1)
				//	Dominant personality
				ApplyDefaultStationery(win,True,True);
			else
				SetPers((*messH)->tocH,(*messH)->sumNum,Index2Pers(info.rowNum-1),true);
			ShowMyWindow(GetMyWindowWindowPtr(win));
		}
	}
}

#ifdef IMAP
/************************************************************************
 * IsIMAPPers - is this personality IMAP?
 ************************************************************************/
Boolean IsIMAPPers(PersHandle pers)
{
		PersHandle oldPers = CurPers;
		Boolean	result;

		CurPers = pers;
		result = PrefIsSet(PREF_IS_IMAP);
		CurPers = oldPers;
		return result;
}

/************************************************************************
 * RenameIMAPPers - rename an IMAP personality's cache
 ************************************************************************/
Boolean RenameIMAPPers(PersHandle pers,StringPtr newName)
{
	//	Need to rename IMAP mail cache
	FSSpec	spec,newSpec;
	Str32		cacheName;
	OSErr		err;

	if (!HasFeature (featureMultiplePersonalities))
		return (false);

	PersNameToCacheName(pers, cacheName);
	FSMakeFSSpec(IMAPMailRoot.vRef, IMAPMailRoot.dirId, cacheName, &spec);
	SimpleMakeFSSpec(IMAPMailRoot.vRef, IMAPMailRoot.dirId,newName,&newSpec);
	TellFiltMBRename(&spec,&newSpec,True,True,false);
	if ((err = HRename(spec.vRefNum,spec.parID,spec.name,newName)) && err != fnfErr)	//	Don't report error if local IMAP cache file not created yet
	{
			(FileSystemError(RENAMING_BOX,spec.name,err));
		return false;
	}
	BuildBoxMenus();
	MBTickle(nil,nil);
	TellFiltMBRename(&spec,&newSpec,True,False,false);
	return true;
}

/************************************************************************
 * DeleteIMAPPers - delete an IMAP personality's cache
 ************************************************************************/
void DeleteIMAPPers(PersHandle pers, Boolean bCacheOnly)
{
	FSSpec spec;
	Str32 cacheName;
	PersHandle oldPers = CurPers;
	
	// go through the personality's mailboxes, making sure they're all closed
	ClosePersMailboxes(pers);
	
	// remove the IMAP personality's cache
	PersNameToCacheName(pers, cacheName);
	if (FSMakeFSSpec(IMAPMailRoot.vRef, IMAPMailRoot.dirId, cacheName, &spec)==noErr)
		RemoveIMAPCacheDir(spec);
	LDRef(pers);
	DisposeMailboxTree(&((*pers)->mailboxTree));
	UL(pers);
	
	if (!bCacheOnly)
	{
		// this is no longer an IMAP personality
		CurPers = pers;
		SetPref(PREF_IS_IMAP,"");
		CurPers = oldPers;
	}
	
	// rebuild the mailbox menus
	BuildBoxMenus();
	MBTickle(nil,nil);
}

/************************************************************************
 * IMAPPersActive - is this personality active?
 ************************************************************************/
Boolean IMAPPersActive(PersHandle pers)
{
	Boolean result = false;
	TOCHandle tocH = nil;
	PersHandle p = nil;
	MailboxNodeHandle n = nil;
	
	// this persoanlity is "active" if there's a mailbox currently visible for it.
	for (tocH=TOCList; tocH && !result; tocH = (*tocH)->next)
	{
		// look at each open, visible TOC
		if ((*tocH)->imapTOC && (*tocH)->win && IsWindowVisible(GetMyWindowWindowPtr((*tocH)->win)))
		{
			n = TOCToMbox(tocH);
			p = TOCToPers(tocH);
			
			// does this toc refers to a mailbox owned by pers?
			if (n && p && (p == pers)) result = true;
		}
	}
	
	return (result);
}

#endif

