eudora-mac/mbwin.c

1 line
70 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 "mbwin.h"
#include "listview.h"
#define FILE_NUM 23
/* Copyright (c) 1990-1992 by the University of Illinois Board of Trustees */
/**********************************************************************
* handling the mailbox window
**********************************************************************/
// First few items in list
enum { kItemEudoraFolder=1,kItemInBox,kItemOutBox,kItemJunkBox,kItemTrash,kItemMailBoxes };
// ViewListIcon - Icon constants for list view
enum
{
kFolderIcon=kGenericFolderIconResource,
kTrashBoxIcon=kTrashIconResource,
kMailBoxIcon=MAILBOX_ONLY_ICON,
kIMAPMailboxIcon=IMAP_MAILBOX_FILE_ICON,
kIMAPPolledMailboxIcon=RESYNC_ICON,
kIMAPPolledFolderIcon=IMAP_POLLED_MAILBOX_FILE_ICON
};
#define dashChar ((unsigned char)'-')
Boolean gfMessageDrag,gfBoxDrag;
// define this to include the Resync button. Remove this all eventually if it's not missed.
//#define SHOW_RESYNC_BUTTON
#pragma segment MboxWin
/************************************************************************
* the structure for the mailbox window
************************************************************************/
typedef enum
{
NewMBIndex,
NewFolderIndex,
RemoveIndex,
#ifdef SHOW_RESYNC_BUTTON
ResyncIndex,
#endif
OptionsMenuIndex,
ControlCount
} ControlEnum;
typedef struct
{
ViewList list;
MyWindowPtr win;
ControlHandle controls[ControlCount];
Boolean dontTickle;
Boolean inited;
Boolean IMAPButtonsVisible;
#ifdef SHOW_RESYNC_BUTTON
Boolean resyncEnabled;
Boolean imapMailboxSelected;
#endif
} MBType;
MBType MB;
#define Win MB.win
#define DontTickle MB.dontTickle
#define Controls MB.controls
#ifdef SHOW_RESYNC_BUTTON
#define cntMBControls 5
#else
#define cntMBControls 4
#endif
#define CtlRemove MB.controls[RemoveIndex]
#define CtlNewMB MB.controls[NewMBIndex]
#define CtlNewFolder MB.controls[NewFolderIndex]
#ifdef SHOW_RESYNC_BUTTON
#define CtlResync MB.controls[ResyncIndex]
#endif
#define CtlOptionsMenu MB.controls[OptionsMenuIndex]
/************************************************************************
* Structure for remembering which folders are expanded.
* Saved as a resource in the settings file
************************************************************************/
struct ExpandListRec
{
short count;
long dirID[];
};
typedef struct ExpandListRec ExpandListRec;
ExpandInfo gExpandList;
typedef struct
{
short cmd;
short mark;
Style style;
} MenuProperties;
/************************************************************************
* prototypes
************************************************************************/
Boolean MBMenu(MyWindowPtr win, int menu, int item, short modifiers);
void MBDidResize(MyWindowPtr win, Rect *oldContR);
void MBZoomSize(MyWindowPtr win,Rect *zoom);
void MBUpdate(MyWindowPtr win);
Boolean MBClose(MyWindowPtr win);
short MBFill(void);
short MBFillSide(MenuHandle mh);
void MBClick(MyWindowPtr win,EventRecord *event);
void MBCursor(Point mouse);
void MBActivate(MyWindowPtr win);
void MBSetControls(void);
void MBHit(short which, Boolean optionPressed);
static void MBIdle(MyWindowPtr win);
static short WhichTree(VLNodeInfo *pInfo);
static void EnableIMAPButtons(MyWindowPtr win);
static Boolean MBKey(MyWindowPtr win, EventRecord *event);
void MBListOpen(ViewListPtr pView);
void MBListClose(short whichSide);
static void MBMenuToFile(short menuID, short *pVRef, long *pDirID);
static void MBMove(VLNodeInfo *pTargetInfo);
static void MBRemove(void);
static OSErr MBDragHandler(MyWindowPtr win,DragTrackingMessage which,DragReference drag);
short FindItemBySubmenu(MenuHandle mh, short subID);
short MBRefill(UPtr andSelect);
static void DoNewMailbox(Boolean fFolder);
Boolean DoRemoveBox(MenuHandle mh,UPtr name,Boolean multiple,Boolean *andShutUp,Boolean *needRefill);
static short DeleteMailFolder(MenuHandle mh,short item);
void DoMoveMailbox(UPtr selectName,short si);
Boolean SameSelected(void);
Boolean MBGetData(VLNodeInfo *data,short item);
void MBHelp(MyWindowPtr win,Point mouse);
// void MBFixIndices(void);
static void SetExpandListSize(ExpandInfoPtr pExpList);
static void GetMenuItemProperties(MenuHandle hMenu,short item,MenuProperties *pFormat);
static void AddMBMenuItem(MenuHandle hMenu,StringPtr sName,MenuProperties *pFormat);
static void MBGrow(MyWindowPtr win,Point *newSize);
static Boolean MBFind(MyWindowPtr win,PStr what);
static Boolean IsSpecialBox(ViewListPtr pView, VLNodeInfo *pInfo);
Boolean IsIMAPTrashBox(VLNodeInfo *data);
OSErr MBTellOthersRename(FSSpecPtr spec,FSSpecPtr newSpec,Boolean folder,Boolean will,Boolean dontWarn);
OSErr GetSelectedMailboxSpecs(Handle *mailboxes, Boolean optionPressed);
OSErr GetSelectedChildMailboxSpecs(Accumulator *b, MailboxNodeHandle toAdd, Boolean childrenToo);
void EnableOptionsMenu(MyWindowPtr win, Boolean optionPressed);
char IMAPOptionsCheckMarkChar(MailboxNeedsEnum needs);
long IMAPMailboxIcon(VLNodeInfo *info, short menuID);
void MBRefreshIMAPMailboxes(Boolean optionPressed);
OSErr MBResyncOrExpungeIMAPMailboxes(Boolean optionPressed, TaskKindEnum task);
void MBMarkIMAPMailboxes(Boolean on, MailboxNeedsEnum needs);
void MBCompactMailboxes(void);
/************************************************************************
* OpenMBWin - open the mailbox window
************************************************************************/
void OpenMBWin(void)
{
WindowPtr WinWP = nil;
if (SelectOpenWazoo(MB_WIN)) return; // Already opened in a wazoo
if (!MB.inited)
{
short err=0;
Rect r;
if (!(Win=GetNewMyWindow(MBWIN_WIND,nil,nil,BehindModal,False,False,MB_WIN)))
{err=MemError(); goto fail;}
WinWP = GetMyWindowWindowPtr (Win);
SetWinMinSize(Win,-1,-1);
SetPort_(GetMyWindowCGrafPtr(Win));
ConfigFontSetup(Win);
MySetThemeWindowBackground(Win,kThemeListViewBackgroundBrush,False);
/*
* controls
*/
if (!(CtlNewMB = NewIconButton(MB_NEWMB_CNTL,WinWP)) ||
!(CtlNewFolder = NewIconButton(MB_NEWFOLDER_CNTL,WinWP)) ||
!(CtlRemove = NewIconButton(MB_REMOVE_CNTL,WinWP)) ||
#ifdef SHOW_RESYNC_BUTTON
!(CtlResync = NewIconButton(MB_RESYNC_CNTL,WinWP)) ||
#endif
!(CtlOptionsMenu = NewIconButtonMenu(MAILBOX_OPTIONS_MENU,REFRESH_ICON,WinWP)))
goto fail;
#ifdef SHOW_RESYNC_BUTTON
MB.resyncEnabled = true;
#endif
MB.IMAPButtonsVisible = true;
MBIdle(Win);
/*
* list
*/
gExpandList.resID = kMBExpandID;
SetRect(&r,0,0,20,20);
if (LVNew(&MB.list,Win,&r,0,MailboxesLVCallBack,kMBDragType))
{err=MemError(); goto fail;}
// if (MBFill()) goto fail;
Win->didResize = MBDidResize;
Win->close = MBClose;
Win->update = MBUpdate;
Win->position = PositionPrefsTitle;
Win->click = MBClick;
Win->bgClick = MBClick;
Win->dontControl = True;
Win->cursor = MBCursor;
Win->activate = MBActivate;
Win->help = MBHelp;
Win->menu = MBMenu;
Win->key = MBKey;
Win->app1 = MBKey;
Win->drag = MBDragHandler;
Win->zoomSize = MBZoomSize;
Win->grow = MBGrow;
Win->find = MBFind;
Win->idle = MBIdle;
Win->showsSponsorAd = true;
ShowMyWindow(WinWP);
MyWindowDidResize(Win,&Win->contR);
MB.inited = true;
return;
fail:
if (WinWP) CloseMyWindow(WinWP);
if (err) WarnUser(COULDNT_MBOX,err);
return;
}
else
WinWP = GetMyWindowWindowPtr (Win);
UserSelectWindow(WinWP);
}
#pragma segment MboxWin
/************************************************************************
* MBDidResize - resize the MB window
************************************************************************/
void MBDidResize(MyWindowPtr win, Rect *oldContR)
{
#define kListInset 10
#pragma unused(oldContR)
Rect r;
short htAdjustment;
// buttons
PositionBevelButtons(win,cntMBControls,MB.controls,kListInset,Win->contR.bottom - INSET - kHtCtl,kHtCtl,RectWi(win->contR));
// list
SetRect(&r,kListInset,win->topMargin+kListInset,Win->contR.right-kListInset,Win->contR.bottom - 2*INSET - kHtCtl);
if (win->sponsorAdExists && r.bottom >= win->sponsorAdRect.top - kSponsorBorderMargin)
r.bottom = win->sponsorAdRect.top - kSponsorBorderMargin;
LVSize(&MB.list,&r,&htAdjustment);
/*
* redraw
*/
MBSetControls();
InvalContent(win);
}
/************************************************************************
* MBOpenFolder - open and selected the folder indicated by the menu ID
************************************************************************/
void MBOpenFolder(Handle hStringList,Boolean IsIMAP)
{
StringPtr pString,sSelect;
VLNodeID id;
short selectID = 0;
OpenMBWin(); // Make sure the MB window is open and in front
// Expand each folder
id = IsIMAP ? kIMAPFolder: kEudoraFolder;
for(pString = LDRef(hStringList);*pString;pString += *pString+1)
{
LVExpand(&MB.list,id,pString,true);
sSelect = pString;
selectID = id;
id = id==kEudoraFolder ? MAILBOX_MENU : MBGetFolderMenuID(id==kIMAPFolder?MAILBOX_MENU:id,pString);
}
if (selectID)
LVSelect(&MB.list,selectID,sSelect,false);
}
/************************************************************************
* MBZoomSize - zoom to only the maximum size of list
************************************************************************/
void MBZoomSize(MyWindowPtr win,Rect *zoom)
{
short zoomHi = zoom->bottom-zoom->top;
short zoomWi = zoom->right-zoom->left;
short hi, wi;
LVMaxSize(&MB.list, &wi, &hi);
wi += 2*kListInset;
hi += 2*kListInset + INSET + ControlHi(CtlNewMB);
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;
}
/************************************************************************
* MBGrow - adjust grow size
************************************************************************/
static void MBGrow(MyWindowPtr win,Point *newSize)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
Rect r,rWin;
short htControl = ControlHi(CtlNewMB);
short bottomMargin,sponsorMargin;
// Get list position
bottomMargin = INSET*2 + htControl;
if (win->sponsorAdExists)
{
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(&MB.list,&r);
// Calculate new window height
newSize->v = r.bottom + bottomMargin;
}
#pragma segment Main
/************************************************************************
* MBClose - close the window
************************************************************************/
Boolean MBClose(MyWindowPtr win)
{
#pragma unused(win)
if (MB.inited)
{
// Save expanded folder list
SaveExpandedFolderList(&gExpandList);
// Dispose of list
LVDispose(&MB.list);
MB.inited = false;
}
return(True);
}
#pragma segment MboxWin
/************************************************************************
* MBUpdate - draw the window
************************************************************************/
void MBUpdate(MyWindowPtr win)
{
CGrafPtr winPort = GetMyWindowCGrafPtr (win);
Rect r;
r = MB.list.bounds;
DrawThemeListBoxFrame(&r,kThemeStateActive);
LVDraw(&MB.list, MyGetPortVisibleRegion(winPort), true, false);
}
/************************************************************************
* MBActivate - activate the window
************************************************************************/
void MBActivate(MyWindowPtr win)
{
#pragma unused(win)
LVActivate(&MB.list, Win->isActive);
}
/**********************************************************************
* MBFind - find in the Mailboxes window
**********************************************************************/
static Boolean MBFind(MyWindowPtr win,PStr what)
{
return FindListView(win,&MB.list,what);
}
/************************************************************************
* MBRefill - refill current menus
************************************************************************/
short MBRefill(UPtr andSelect)
{
short err;
/*
If andSelect specified, find and select it.
Else If there was a selection before, select it
*/
err = MBFillSide(GetMHandle(MAILBOX_MENU));
return(err);
}
/************************************************************************
* MBFill - fill the windows
************************************************************************/
short MBFill(void)
{
short err;
MenuHandle mh=GetMHandle(MAILBOX_MENU);
if (err=MBFillSide(mh)) return(err);
return(noErr);
}
/************************************************************************
* MBFillSide - fill the list from a menu
************************************************************************/
short MBFillSide(MenuHandle mh)
{
InvalidListView(&MB.list);
return noErr;
}
/************************************************************************
* MBKey - key stroke
************************************************************************/
static Boolean MBKey(MyWindowPtr win, EventRecord *event)
{
#pragma unused(win)
short key = (event->message & 0xff);
if (LVKey(&MB.list,event))
{
MBSetControls();
return true;
}
return false;
}
/************************************************************************
* MBClick - click in mailboxes window
************************************************************************/
void MBClick(MyWindowPtr win,EventRecord *event)
{
//#pragma unused(win)
WindowPtr winWP = GetMyWindowWindowPtr (win);
Rect r;
short i;
Point pt;
SetPort(GetMyWindowCGrafPtr(win));
if (!LVClick(&MB.list,event))
{
pt = event->where;
GlobalToLocal(&pt);
if (!win->isActive)
{
SelectWindow_(winWP);
UpdateMyWindow(winWP); // Have to update manually since no events are processed
}
for (i=0;i<ControlCount;i++)
{
GetControlBounds(Controls[i],&r);
if (PtInRect(pt,&r))
{
// properly enable and disable the menu when it's selected
if (Controls[i] == CtlOptionsMenu)
EnableOptionsMenu(Win, ((event->modifiers&optionKey)!=0));
if (!ControlIsGrey(Controls[i]) &&
TrackControl(Controls[i],pt,(void *)(-1)))
MBHit(i,(event->modifiers&optionKey) != 0);
AuditHit((event->modifiers&shiftKey)!=0, (event->modifiers&controlKey)!=0, (event->modifiers&optionKey)!=0, (event->modifiers&cmdKey)!=0, false, GetWindowKind(winWP), AUDITCONTROLID(GetWindowKind(winWP),i), event->what);
break;
}
}
}
MBSetControls();
}
/************************************************************************
* MBCursor - set the cursor properly for the mailboxes window
************************************************************************/
void MBCursor(Point mouse)
{
if (!PeteCursorList(Win->pteList,mouse))
SetMyCursor(arrowCursor);
}
/************************************************************************
* MBSetControls - enable or disable the controls, based on current situation
************************************************************************/
void MBSetControls(void)
{
Boolean fSelect,fRemove;
Boolean fAdd = true;
Boolean isIMAPBox;
short i;
VLNodeInfo data;
fSelect = LVCountSelection(&MB.list)!=0;
Win->hasSelection = fSelect;
// Determine if "Remove" button needs to be greyed
if (fRemove = fSelect)
{
// Make sure that selection doesn't include any non-removeable items
short i;
VLNodeInfo data;
for (i=1;i<=LVCountSelection(&MB.list);i++)
{
MBGetData(&data,i);
if ((IsSpecialBox(&MB.list,&data))
|| data.nodeID == kIMAPFolder // Can't delete IMAP personalities
|| (IsIMAPBox(&data) && !CanModifyMailboxTrees())) // Can't delete IMAP boxes while the tree is in use
{
// Here's an item that can't be removed
fRemove = false;
break;
}
}
}
SetGreyControl(CtlRemove,!fRemove);
// Determine if the "Add" buttons need to be greyed.
// see what's selected
#ifdef SHOW_RESYNC_BUTTON
MB.imapMailboxSelected = false;
#endif
for (i=1;i<=LVCountSelection(&MB.list);i++)
{
MBGetData(&data,i);
isIMAPBox = IsIMAPBox(&data);
if (isIMAPBox)
{
// Can't add mailboxes when the tree is in use
if (!CanModifyMailboxTrees())
{
// Here's an item that can't be removed
fAdd = false;
break;
}
#ifdef SHOW_RESYNC_BUTTON
// but we can enable the resync control
MB.imapMailboxSelected = true;
#endif
}
}
// properly activate Refresh and Resync buttons
EnableIMAPButtons(Win);
SetGreyControl(CtlNewMB,!fAdd);
SetGreyControl(CtlNewFolder,!fAdd);
}
/************************************************************************
* MBHit - a control item was hit
************************************************************************/
void MBHit(short which, Boolean optionPressed)
{
Boolean resyncPlease = false;
SInt16 value=0;
MenuHandle menu = nil;
short markChar=0;
switch (which)
{
case RemoveIndex:
MBRemove();
break;
case NewMBIndex:
DoNewMailbox(false);
break;
case NewFolderIndex:
DoNewMailbox(true);
break;
case OptionsMenuIndex:
if (!GetControlData(CtlOptionsMenu,1,kControlBevelButtonMenuValueTag,sizeof(SInt16),(Ptr)&value,nil) && !GetControlData(CtlOptionsMenu,1,kControlBevelButtonMenuHandleTag,sizeof(menu),(Ptr)&menu,nil) && menu)
{
switch(value)
{
case OPTIONS_RESYNCSUB_ITEM:
optionPressed = true;
case OPTIONS_RESYNC_ITEM:
resyncPlease = true;
break;
case OPTIONS_AUTOSYNC_ITEM:
GetItemMark(menu,value,&markChar);
MBMarkIMAPMailboxes((markChar==0), kNeedsPoll);
break;
case OPTIONS_REFRESH_ITEM:
MBRefreshIMAPMailboxes(optionPressed);
break;
case OPTIONS_SHOWDELETED_ITEM:
GetItemMark(menu,value,&markChar);
MBMarkIMAPMailboxes((markChar==0), kShowDeleted);
break;
case OPTIONS_EXPUNGE_ITEM:
MBResyncOrExpungeIMAPMailboxes(false, IMAPMultExpungeTask);
break;
case OPTIONS_COMPACT_ITEM:
MBCompactMailboxes();
break;
default:
break;
}
}
// fall through if resync was requested through the menu
if (!resyncPlease)
break;
#ifdef SHOW_RESYNC_BUTTON
case ResyncIndex:
#endif
MBResyncOrExpungeIMAPMailboxes(optionPressed, IMAPMultResyncTask);
break;
}
}
/************************************************************************
* GetSelectedMailboxSpecs - build a list of selected mailboxes to process.
************************************************************************/
OSErr GetSelectedMailboxSpecs(Handle *mailboxes, Boolean optionPressed)
{
OSErr err = noErr;
Accumulator boxes;
short count, i;
VLNodeInfo data;
FSSpec spec;
MailboxNodeHandle mbox;
PersHandle selectedPers = nil, pers;
*mailboxes = NULL;
if (count = LVCountSelection(&MB.list))
{
err = AccuInit(&boxes);
if (err == noErr)
{
// collect all selected mailboxes
for (i=1;i<=count;i++)
{
// get mailbox spec
MBGetData(&data,i);
MakeMBSpec(&data,&spec);
// option-refresh on an IMAP account refreshes all mailboxes.
if (optionPressed && (data.nodeID == kIMAPFolder))
{
selectedPers = FindPersByName(spec.name);
GetSelectedChildMailboxSpecs(&boxes, (*selectedPers)->mailboxTree, true);
}
// is this an IMAP mailbox?
if (IsIMAPBox(&data))
{
spec.parID = SpecDirId(&spec);
LocateNodeBySpecInAllPersTrees(&spec, &mbox, &pers);
// skip this mailbox if t belongs to the last IMAP account we added to the list.
if (pers != selectedPers)
{
if (mbox)
{
GetSelectedChildMailboxSpecs(&boxes, mbox, optionPressed);
}
}
}
}
AccuTrim(&boxes);
*mailboxes = boxes.data;
}
}
// else
// nothing was selected. Return nothing.
return (err);
}
/************************************************************************
* GetSelectedChildMailboxSpecs - add the mailbox and the children, if
* appropriate, to the list.
************************************************************************/
OSErr GetSelectedChildMailboxSpecs(Accumulator *b, MailboxNodeHandle toAdd, Boolean childrenToo)
{
OSErr err = noErr;
FSSpec spec;
MailboxNodeHandle scan;
// check parameters
if (toAdd && b)
{
// add this mailbox if it's really a mailbox
if ((*toAdd)->mailboxName)
{
spec = ((*toAdd)->mailboxSpec);
err = AccuAddPtr(b, &spec, sizeof(FSSpec));
// add the children if we ought
if ((err == noErr) && childrenToo)
{
if (scan = (*toAdd)->childList)
{
while (scan && (err == noErr))
{
err = GetSelectedChildMailboxSpecs(b, scan, true);
scan = (*scan)->next;
}
}
}
}
else if (childrenToo)
{
// This is an IMAP account. Add all of the mailboxes.
scan = (*toAdd)->next;
while (scan && (err == noErr))
{
err = GetSelectedChildMailboxSpecs(b, scan, true);
scan = (*scan)->next;
}
}
}
return (err);
}
/************************************************************************
* MBListOpen - open some stuff from a list handle
************************************************************************/
void MBListOpen(ViewListPtr pView)
{
short i;
VLNodeInfo data;
FSSpec spec;
for (i=1;i<=LVCountSelection(pView);i++)
{
LVGetItem(pView,i,&data,true);
if (!data.isParent || data.iconID == kIMAPMailboxIcon || IsIMAPTrashBox(&data))
{
MakeMBSpec(&data,&spec);
(void) GetMailbox(&spec,True);
}
}
}
/************************************************************************
* MBFixUnread - Update and "unread" status of a mailbox
************************************************************************/
void MBFixUnread(MenuHandle mh,short item,Boolean unread)
{
if (MB.inited)
MBFixUnreadLo(&MB.list,mh,item,unread,GetWindowKind(GetMyWindowWindowPtr(MB.win)) == MB_WIN);
SearchFixUnread(mh,item,unread);
MBDrawerFixUnread(mh,item,unread);
}
/************************************************************************
* MBFixUnread - Update and "unread" status of a mailbox
************************************************************************/
void MBFixUnreadLo(ViewListPtr pView,MenuHandle mh,short item,Boolean unread,Boolean draw)
{
Str63 name;
Style theStyle = unread ? UnreadStyle : 0;
short menuID;
Boolean mailboxMenu = GetMenuID(mh) == MAILBOX_MENU;
if (mailboxMenu && !item)
{
// Update "Eudora Folder"
GetMBDirName(Root.vRef,Root.dirId,name); // Name of Mail Folder
LVUpdateStyle(pView,kEudoraFolder,name,theStyle,draw);
}
else
{
MyGetItem(mh,item,name);
if (mailboxMenu && IMAPExists() && (menuID = SubmenuId(mh,item)))
{
short vRef;
long dirID;
MBMenuToFile(menuID,&vRef,&dirID);
if (IsIMAPVD(vRef,dirID))
{
LVUpdateStyle(pView,kIMAPFolder,name,theStyle,draw);
return;
}
}
LVUpdateStyle(pView,GetMenuID(mh),name,theStyle,draw);
}
}
/************************************************************************
* DoNewMailbox - make a new mailbox or mailbox folder
************************************************************************/
static void DoNewMailbox(Boolean folder)
{
FSSpec spec;
short vRefNum;
long dirID;
VLNodeInfo data;
short menuID;
Boolean imapSuccess = false;
MenuHandle mh;
short level,subMenuID;
Str63 name;
// Determine which folder to put it in
vRefNum = MailRoot.vRef; // Assume main mailboxes folder
dirID = MailRoot.dirId;
menuID = MAILBOX_MENU;
if (MBGetData(&data,1))
{
// if the currently select node is an IMAP personality, make sure we have a mailbox tree
if (data.nodeID == kIMAPFolder)
{
PersHandle oldPers = CurPers;
// the personality is collapsed. Do nothing.
if (data.isCollapsed) return;
if (CurPers = FindPersByName(data.name))
{
if (PrefIsSet(PREF_IS_IMAP))
if (!MailboxTreeGood(CurPers))
if (CreateLocalCache() != noErr)
{
CurPers = oldPers;
return;
}
}
CurPers = oldPers;
}
// Put it in parent of first selected item or self if a folder
MBMenuToFile(data.nodeID, &vRefNum, &dirID);
menuID = data.nodeID;
if ((!data.isParent || !data.isCollapsed) && IsIMAPBox(&data))
{
PersHandle pers = nil;
MailboxNodeHandle node = nil;
FSMakeFSSpec(vRefNum,dirID,data.name,&spec);
spec.parID = SpecDirId(&spec);
LocateNodeBySpecInAllPersTrees(&spec, &node, &pers);
if (node && pers && CanHaveChildren(node))
{
dirID = spec.parID;
menuID = MBGetFolderMenuID(data.nodeID,data.name);
}
}
else
{
if (data.isParent && !data.isCollapsed)
{
FSMakeFSSpec(vRefNum,dirID,data.name,&spec);
dirID = SpecDirId(&spec);
if (!dirID) dirID = spec.parID;
menuID = MBGetFolderMenuID(data.nodeID,data.name);
}
}
}
// Warn user if we will be more than 5 levels deep
subMenuID = menuID;
mh=GetMenuHandle(subMenuID);
for(level=0;mh;level++)
mh=ParentMailboxMenu(mh,&subMenuID);
if (level>5 && !PrefIsSet(PREF_NO_MAILBOX_LEVEL_WARNING) &&
!Mom(CREATE,0,PREF_NO_MAILBOX_LEVEL_WARNING,R_FMT,MAILBOX_LEVEL_WARNING))
return; // too deep
// Make a unique "untitled" name
MakeUniqueUntitledSpec (vRefNum, dirID, folder ? UNTITLED_FOLDER : UNTITLED_MAILBOX, &spec);
// try to add this mailbox as an IMAP mailbox first.
if (IMAPAddMailbox(&spec, folder, &imapSuccess, false))
{
if (imapSuccess)
{
MBTickle(nil,nil);
menuID = MBGetFolderMenuID(data.nodeID,data.name);
LVRename(&MB.list,menuID,spec.name,false,false); // Allow user to rename the untitled mailbox/folder
}
}
else
{
PSCopy(name,spec.name); // BadMailboxName steps on the name if it's a folder
if (!BadMailboxName(&spec,folder)) // Creates the mailbox/folder
{
if (!folder)
{
AddBoxHigh(&spec);
}
else
{
BuildBoxMenus();
MBTickle(nil,nil);
}
LVRename(&MB.list,menuID,name,false,false); // Allow user to rename the untitled mailbox/folder
}
}
}
/************************************************************************
* MBRemove - delete selected mailbox(es)
************************************************************************/
static void MBRemove(void)
{
short i;
Boolean needRefill=false;
Boolean andShutUp=false;
Boolean fFolder=false;
short n;
for (i=1;i<=(n=LVCountSelection(&MB.list));i++)
{
VLNodeInfo data;
MBGetData(&data,i);
if ((data.nodeID != kIMAPFolder) && (!IsSpecialBox(&MB.list,&data)))
{
if (!DoRemoveBox(GetMHandle(data.nodeID),data.name,i<n,&andShutUp,&needRefill)) break;
if (data.isParent)
fFolder = true;
}
}
if (fFolder)
BuildBoxMenus();
if (needRefill)
MBTickle(nil,nil);
}
/************************************************************************
* MBRename - rename selected mailbox
************************************************************************/
static void MBRename(StringPtr newName)
{
VLNodeInfo data;
short vRef;
long dirID;
FSSpec spec,origSpec,newSpec;
TOCHandle tocH;
Boolean isFolder;
OSErr err=0;
Str255 suffix;
// complain if the mailbox name is too long
if (*newName>31-*GetRString(suffix,TOC_SUFFIX))
{
TooLong(newName);
goto Done;
}
if (MBGetData(&data,1) && *newName && !EqualString(newName,data.name,true,true))
{
MBMenuToFile(data.nodeID, &vRef, &dirID);
FSMakeFSSpec(vRef,dirID,data.name,&spec);
SimpleMakeFSSpec(vRef,dirID,newName,&newSpec);
IsAlias(&spec,&origSpec);
isFolder=FSpIsItAFolder(&origSpec);
if (!isFolder && (!(tocH=TOCBySpec(&spec)) || (*tocH)->which))
{
err = WarnUser(MAYNT_RENAME_BOX,0);
goto Done;
}
// complain if the mailbox name has some inappropriate characters
if (BadMailboxNameChars(&newSpec))
goto Done;
// rename the IMAP mailbox
if (IsIMAPCacheFolder(&spec))
{
MBTellOthersRename(&spec,&newSpec,True,True,false);
IMAPRenameMailbox(&spec, newSpec.name);
MBTellOthersRename(&spec,&newSpec,True,False,false);
goto Done;
}
// if (!StringSame(spec.name,newName))
// HDelete(spec.vRefNum,spec.parID,newName);
if (isFolder)
{
MBTellOthersRename(&spec,&newSpec,True,True,false);
if (err = HRename(spec.vRefNum,spec.parID,spec.name,newName))
{
(FileSystemError(RENAMING_BOX,spec.name,err));
goto Done;
}
BuildBoxMenus();
MBTickle(nil,nil);
MBTellOthersRename(&spec,&newSpec,True,False,false);
}
else
{
MBTellOthersRename(&spec,&newSpec,False,True,false);
if (err = RenameMailbox(&spec,newName,isFolder)) goto Done;
if (tocH)
{
TOCSetDirty(tocH,true);
PCopy((*tocH)->mailbox.spec.name,newName);
SetWTitle_(GetMyWindowWindowPtr((*tocH)->win),newName);
}
DontTickle = True;
RemoveBoxHigh(&spec);
DontTickle = False;
AddBoxHigh(&newSpec);
MBTellOthersRename(&spec,&newSpec,False,False,false);
TellSearchMBRename(&spec,&newSpec);
}
}
Done:
if (err)
InvalContent(Win); // Clean up window
}
/************************************************************************
* ParentMailboxMenu - find the menu enclosing this one
************************************************************************/
MenuHandle ParentMailboxMenu(MenuHandle mh,short *itemPtr)
{
short myID, curID;
curID = myID = GetMenuID(mh);
while (--curID && (mh = GetMHandle(curID)))
{
if (*itemPtr = FindItemBySubmenu(mh,myID)) return(mh);
}
mh = GetMHandle(MAILBOX_MENU);
if (*itemPtr = FindItemBySubmenu(mh,myID)) return(mh);
return(nil);
}
/************************************************************************
* FindItemBySubmenu - find a menu item with a given submenu
************************************************************************/
short FindItemBySubmenu(MenuHandle mh, short subID)
{
short item, newID;
for (item=CountMenuItems(mh);item;item--)
{
if (HasSubmenu(mh,item))
{
newID = SubmenuId(mh,item);
if (newID==subID) return(item);
}
}
return(0);
}
/************************************************************************
* DoRemoveBox - interact with the user before removing a mailbox
************************************************************************/
Boolean DoRemoveBox(MenuHandle mh,UPtr name,Boolean multiple,Boolean *andShutUp,Boolean *needRefill)
{
Boolean isFolder=False;
Boolean isEmpty;
short clicked;
FSSpec spec, newSpec;
CInfoPBRec hfi;
FInfo info;
short res;
Boolean trashChain=False;
Boolean justTrash=False;
Boolean isIMAPBox = false;
GetTransferParams(GetMenuID(mh),FindItemByName(mh,name),&spec,nil);
FSpGetFInfo(&spec,&info);
isFolder = FSpIsItAFolder(&spec);
isIMAPBox = IsIMAPMailboxFile(&spec);
/*
* is it an alias?
*/
if (!isFolder && info.fdFlags & kIsAlias)
{
if (!IsAlias(&spec,&newSpec))
{
/*
* ok, here we have an alias that points nowhere. just trash it.
*/
isEmpty = True;
trashChain = False;
justTrash = True;
}
else
{
res = AlertStr(ALIAS_OR_REAL_ALRT,Note,spec.name);
if (res==aorCancel) return(False);
trashChain = (res==aorBoth);
if (trashChain) isFolder = info.fdType==kContainerFolderAliasType;
else justTrash = isEmpty = True;
}
}
if (!justTrash)
{
if (!isFolder)
{
/*
* is the box empty?
*/
if (AFSpGetHFileInfo(&spec,&hfi)) isEmpty = True;
else isEmpty = hfi.hFileInfo.ioFlLgLen==0;
}
else isEmpty = FolderFileCount(&spec)<=0;
// if this is an IMAP mailbox, make sure this mailbox really is empty
if (isEmpty && isIMAPBox) isEmpty = IsIMAPMailboxEmpty(&spec);
}
if (!justTrash && !*andShutUp)
{
clicked = AlertStr(isEmpty?
(multiple ? DELETE_EMPTY_ALRT : ALRTStringsOnlyStrn+DELETE_EMPTY_SINGLE_ASTR)
: (multiple ? (isIMAPBox?DELETE_NON_EMPTY_IMAP_ASTR+ALRTStringsOnlyStrn:DELETE_NON_EMPTY_ALRT) : ALRTStringsOnlyStrn+(isIMAPBox?DELETE_NON_EMPTY_SINGLE_IMAP_ASTR:DELETE_NON_EMPTY_SINGLE_ASTR)),
Caution,name);
if (clicked==DELETE_REMOVE_ALL) *andShutUp = True;
else if (clicked!=DELETE_REMOVE_IT) return(False);
}
// if this is an IMAP folder, then do the IMAP thing
if (isIMAPBox)
{
Boolean result = false;
// close any child mailboxes ...
IMAPCloseChildMailboxes(&spec);
DontTickle = True;
result = IMAPDeleteMailbox(&spec);
DontTickle = False;
*needRefill = True;
return (result);
}
if (isFolder)
{
short item = FindItemByName(mh,name);
if (DeleteMailFolder(mh,item)) return(False);
*needRefill = True;
}
else
{
RemoveMailbox(&spec,trashChain);
DontTickle = True;
RemoveBoxHigh(&spec);
DontTickle = False;
*needRefill = True;
}
return(True);
}
/************************************************************************
* DeleteMailFolder - move a mail folder to the trash
************************************************************************/
static short DeleteMailFolder(MenuHandle mh,short item)
{
short err=0;
FSSpec spec, realSpec;
GetTransferParams(GetMenuID(mh),item,&spec,nil);
if (IsAlias(&spec,&realSpec))
FSpTrash(&realSpec); // Was an alias, move real folder to trash, then alias
err = FSpTrash(&spec);
return(err);
}
/************************************************************************
* MBMove - move selected mailbox(es) to target
************************************************************************/
static void MBMove(VLNodeInfo *pToInfo)
{
short i,n;
short toVRef;
long toDirID;
Boolean fChanged = false;
Boolean fFolder = false;
Boolean fMovedFolder;
FSSpec spec, newSpec;
OSErr moveErr=nil;
short fromVRef,flushVRef=0;
long fromDirID;
VLNodeInfo data,folderData;
Boolean ignoreFilters = false;
Boolean dontWarn = false;
if (pToInfo->nodeID==kEudoraFolder)
{
// Eudora Folder
toVRef = MailRoot.vRef;
toDirID = MailRoot.dirId;
}
else
{
MBMenuToFile(pToInfo->nodeID, &toVRef, &toDirID);
FSMakeFSSpec(toVRef,toDirID,pToInfo->name,&spec);
IsAlias(&spec,&spec);
toDirID = SpecDirId(&spec);
toVRef = spec.vRefNum; // In case it was alias to another volume
}
n = LVCountSelection(&MB.list);
fMovedFolder = false;
for (i=1;i<=n && !moveErr;i++)
{
MBGetData(&data,i);
if (IsSpecialBox(&MB.list,&data))
// Can't move this one
continue;
MBMenuToFile(data.nodeID, &fromVRef, &fromDirID);
// If the mailbox to be moved is an IMAP box, allow it to be moved on the same server only
if (IsIMAPBox(&data))
{
FSSpec fromSpec, toSpec;
SimpleMakeFSSpec(fromVRef, fromDirID, data.name, &fromSpec);
SimpleMakeFSSpec(toVRef, toDirID, pToInfo->name, &toSpec);
MBTellOthersRename(&spec,&newSpec,true,true,false);
if (!IMAPMoveMailbox(&fromSpec, &toSpec, i==n, i>n, &dontWarn)) return;
MBTellOthersRename(&spec,&newSpec,true,false,dontWarn);
continue;
}
// we don't allow moves of local mailboxes *to* an IMAP server
if (pToInfo->nodeID == kIMAPFolder)
{
WarnUser(MOVE_MAILBOX,0);
return;
}
// and we don't allow moves of local mailboxes to an IMAP folder
if (IsIMAPBox(pToInfo))
{
WarnUser(MOVE_MAILBOX,0);
return;
}
if (toVRef != fromVRef)
{
WarnUser(CANT_VOL_MOVE,0);
return;
}
if (fMovedFolder && LVDescendant(&MB.list,&data,&folderData))
// We have already moved an ancestor of this file. Don't
// try to move it again
continue;
if (fMovedFolder = data.isParent)
{
// Moved a folder
folderData = data;
}
if (LVDescendant(&MB.list,&data,pToInfo)==1)
// Don't try to move a child into its parent--it's already there
continue;
// Move file or directory
if (data.isParent)
fFolder = true;
MBTellOthersRename(&spec,&newSpec,fFolder,true,false);
if (!fFolder)
{
DontTickle = true;
FSMakeFSSpec(fromVRef,fromDirID,data.name,&spec);
RemoveBoxHigh(&spec);
DontTickle = false;
}
moveErr=HMove(fromVRef,fromDirID,data.name,toDirID,nil);
flushVRef = fromVRef;
if (!fFolder)
{
// If there was an error, we need to add the mailbox back in to its original location
DontTickle = true;
if (!moveErr)
FSMakeFSSpec(fromVRef,toDirID,data.name,&spec);
AddBoxHigh(&spec);
DontTickle = false;
}
if (moveErr)
{
FileSystemError(MOVE_MAILBOX,data.name,moveErr);
}
else
{
// If file, move TOC also
if (!data.isParent)
{
Str15 suffix;
short err;
TOCHandle tocH;
FSSpec spec;
PCat(data.name,GetRString(suffix,TOC_SUFFIX));
if ((err=HMove(fromVRef,fromDirID,data.name,toDirID,nil)) &&
err!=fnfErr && err!=paramErr && err!=bdNamErr)
{FileSystemError(MOVE_MAILBOX,data.name,err); return;}
*data.name -= *suffix;
FSMakeFSSpec(fromVRef,fromDirID,data.name,&spec);
if (tocH=FindTOC(&spec))
(*tocH)->mailbox.spec.parID = toDirID;
}
fChanged = true;
SimpleMakeFSSpec(fromVRef,fromDirID,data.name,&spec);
SimpleMakeFSSpec(toVRef,toDirID,data.name,&newSpec);
if (!ignoreFilters)
{
if (MBTellOthersRename(&spec,&newSpec,fFolder,false,dontWarn)==userCanceledErr)
ignoreFilters = true;
dontWarn = true; // one warning is enough
}
TellSearchMBRename(&spec,&newSpec);
}
}
if (flushVRef)
// Flush the volume so the directory is correct for
// rebuilding the mailbox tree
FlushVol(nil,flushVRef);
if (fFolder)
BuildBoxMenus();
if (fChanged)
MBTickle(nil,nil);
}
Boolean MBGetData(VLNodeInfo *data,short selectedItem)
{
short junk=64;
return LVGetItem(&MB.list,selectedItem,data,true);
}
void MBTickle(UPtr fromSelect,UPtr select)
{
if (MB.inited && !DontTickle)
{
// MBFixIndices();
(void) MBRefill(select);
}
SearchMBUpdate();
MBDrawerReload();
}
/************************************************************************
* MBTellOthersRename - let the rest of the app know what we're up to
************************************************************************/
OSErr MBTellOthersRename(FSSpecPtr spec,FSSpecPtr newSpec,Boolean folder,Boolean will,Boolean dontWarn)
{
if (MBRenameStack)
{
short n = (*MBRenameStack)->elCount;
while (n--)
{
MBRenameProcPtr proc;
OSErr err;
StackItem(&proc,n,MBRenameStack);
err = (*proc)(spec,newSpec,folder,will,dontWarn);
if (err) return err;
}
}
return noErr;
}
#pragma segment Balloon
/************************************************************************
* MBHelp - provide help for the mailbox window
************************************************************************/
void MBHelp(MyWindowPtr win,Point mouse)
{
#pragma unused(win)
if (PtInRect(mouse,&MB.list.bounds))
MyBalloon(&MB.list.bounds,100,0,MBWIN_HELP_STRN+1,0,nil);
else
ShowControlHelp(mouse,MBWIN_HELP_STRN+2,CtlNewMB,CtlNewFolder,CtlRemove,CtlOptionsMenu,
#ifdef SHOW_RESYNC_BUTTON
CtlResync,
#endif
nil);
}
#pragma segment MboxWin
/************************************************************************
* MBMenu - menu choice in the mailbox window
************************************************************************/
Boolean MBMenu(MyWindowPtr win, int menu, int item, short modifiers)
{
#pragma unused(win,modifiers)
switch (menu)
{
case FILE_MENU:
switch(item)
{
case FILE_OPENSEL_ITEM:
MBListOpen(&MB.list);
return(True);
break;
}
break;
case EDIT_MENU:
switch(item)
{
case EDIT_SELECT_ITEM:
if (LVSelectAll(&MB.list))
{
MBSetControls();
return(true);
}
break;
case EDIT_COPY_ITEM:
LVCopy(&MB.list);
return true;
}
break;
}
return(False);
}
/************************************************************************
* MBMenuToFile - convert a menu id into a file reference
************************************************************************/
void MBMenuToFile(short menuID, short *pVRef, long *pDirID)
{
if (menuID==kIMAPFolder)
{
*pVRef = IMAPMailRoot.vRef;
*pDirID = IMAPMailRoot.dirId;
}
else
MenuID2VD(menuID==kEudoraFolder?MAILBOX_MENU:menuID,pVRef,pDirID);
}
/**********************************************************************
* MBDragHandler - handle drags
*
* Can do internal dragging of mailboxes or external dragging and dropping
* of messages
**********************************************************************/
static OSErr MBDragHandler(MyWindowPtr win,DragTrackingMessage which,DragReference drag)
{
#pragma unused(win)
OSErr err = noErr;
gfMessageDrag = DragIsInteresting(drag,MESS_FLAVOR,TOC_FLAVOR,nil); // Dragging messages
gfBoxDrag = LVDragFlavor() == kMBDragType; // Dragging mailboxes
if (!gfMessageDrag && !gfBoxDrag)
return(dragNotAcceptedErr); // Nothing here we want
switch (which)
{
case kDragTrackingEnterWindow:
case kDragTrackingLeaveWindow:
case kDragTrackingInWindow:
err = LVDrag(&MB.list,which,drag);
break;
case 0xfff:
// Drop
if (gfBoxDrag)
// Mailbox drag
err = LVDrag(&MB.list,which,drag);
else
{
// Message drag
VLNodeInfo targetInfo;
if (LVDrop(&MB.list,&targetInfo))
err = MBDragMessages(drag, &targetInfo);
else
return dragNotAcceptedErr;
}
break;
}
return err;
}
/**********************************************************************
* MBDragMessages - handle message drags
**********************************************************************/
OSErr MBDragMessages(DragReference drag, VLNodeInfo *targetInfo)
{
FSSpec spec,toSpec;
TOCHandle tocH;
short sumNum;
OSErr err;
UHandle data=nil;
// Get spec of mailbox dropped on
MakeMBSpec(targetInfo,&spec);
if (!(err=MyGetDragItemData(drag,1,MESS_FLAVOR,(void*)&data)))
{
tocH = (***(MessHandle**)data)->tocH;
sumNum = (***(MessHandle**)data)->sumNum;
}
else if (!(err=MyGetDragItemData(drag,1,TOC_FLAVOR,(void*)&data)))
{
tocH = **(TOCHandle**)data;
sumNum = -1;
}
ZapHandle(data);
// Can't move to own mailbox
toSpec = GetMailboxSpec(tocH,-1);
if (toSpec.vRefNum==spec.vRefNum && toSpec.parID==spec.parID && StringSame(toSpec.name,spec.name))
// Dragging to own mailbox
return dragNotAcceptedErr;
if (!err)
{
if (sumNum==-1) MoveSelectedMessages(tocH,&spec,(DragOrMods(drag)&optionKey)!=0);
else
{
// if (!(DragOrMods(drag)&optionKey)) EzOpen(tocH,sumNum,0,DragOrMods(drag),True,True);
if (!(DragOrMods(drag)&optionKey)) {
#ifndef clarenceBug821
#ifdef TWO
AddXfUndo(tocH,TOCBySpec(&spec),sumNum);
#endif
#endif
EzOpen(tocH,sumNum,0,DragOrMods(drag),True,True);
}
MoveMessage(tocH,sumNum,&spec,(DragOrMods(drag)&optionKey)!=0);
}
}
return(err);
}
/************************************************************************
* MBGetExpList - return pointer to folder expansion list data
************************************************************************/
ExpandInfoPtr MBGetExpList(void)
{
return &gExpandList;
}
/************************************************************************
* MBGetList - return pointer to mailbox list
************************************************************************/
ViewListPtr MBGetList(void)
{
return &MB.list;
}
/************************************************************************
* FindExpandDirID - Find the indicated dirID in the expanded folder list
************************************************************************/
long *FindExpandDirID(long dirID, ExpandInfoPtr pExpList)
{
short i;
long *pDirID;
if (!pExpList->hExpandList)
{
// Get expanded folder list
if (pExpList->resID && (pExpList->hExpandList = Get1Resource(kExpandListType,pExpList->resID)))
DetachResource(pExpList->hExpandList);
else
// Need to create a new one
pExpList->hExpandList = NewHandleClear(2);
pExpList->fExpandListChanged = false;
}
// Find the dirID in the list
for (i=0,pDirID=(*pExpList->hExpandList)->dirID;i<(*pExpList->hExpandList)->count;i++,pDirID++)
{
if (*pDirID == dirID)
return pDirID;
}
return nil;
}
/************************************************************************
* SaveExpandStatus - save status of expanded folders
************************************************************************/
void SaveExpandStatus(VLNodeInfo *data,ExpandInfoPtr pExpList)
{
long *pDirID;
pDirID = FindExpandDirID(data->refCon,pExpList);
if (data->isCollapsed)
{
// Remove from list
if (pDirID)
{
(*pExpList->hExpandList)->count--;
BMD(pDirID+1,pDirID,sizeof(long)*((*pExpList->hExpandList)->count-(pDirID-(*pExpList->hExpandList)->dirID)));
SetExpandListSize(pExpList);
pExpList->fExpandListChanged = true;
}
}
else
{
// Add to list
if (!pDirID)
{
if (!PtrPlusHand_(&data->refCon,(Handle)pExpList->hExpandList,sizeof(long)))
{
(*pExpList->hExpandList)->count++;
pExpList->fExpandListChanged = true;
}
}
}
}
/************************************************************************
* SetExpandListSize - set size based on count
************************************************************************/
static void SetExpandListSize(ExpandInfoPtr pExpList)
{
SetHandleSize((Handle)pExpList->hExpandList,sizeof(short)+sizeof(long)*(*pExpList->hExpandList)->count);
}
/************************************************************************
* MBGetFolderMenuID - get the menu ID for this folder
************************************************************************/
short MBGetFolderMenuID(short theID,StringPtr name)
{
short item,id;
MenuHandle mh;
id = 0;
if (theID==kEudoraFolder || theID==kIMAPFolder)
theID = MAILBOX_MENU;
if (mh = GetMenuHandle(theID))
{
item = FindItemByName(mh,name);
id = SubmenuId(mh,item);
}
return(id);
}
/************************************************************************
* SaveExpandedFolderList - save expanded folder list. Remove any folders
* that no longer exist
************************************************************************/
void SaveExpandedFolderList(ExpandInfoPtr pExpList)
{
if (pExpList->fExpandListChanged && pExpList->resID)
{
short from,to;
OSErr err;
// Remove any directories from the list that no longer exist
for(from=0,to=0;from<(*pExpList->hExpandList)->count;from++)
{
CInfoPBRec hfi;
long dirID;
hfi.dirInfo.ioCompletion = nil;
hfi.dirInfo.ioNamePtr = nil;
hfi.dirInfo.ioVRefNum=MailRoot.vRef;
hfi.dirInfo.ioDrDirID = dirID = (*pExpList->hExpandList)->dirID[from];
hfi.dirInfo.ioFDirIndex=-1;
if (!PBGetCatInfo((CInfoPBPtr)&hfi,false))
{
// This one still exists. Use it
(*pExpList->hExpandList)->dirID[to++] = dirID;
}
}
if (from != to)
{
// Looks like we deleted one or more directory ID's
(*pExpList->hExpandList)->count = to;
SetExpandListSize(pExpList);
}
ZapSettingsResource(kExpandListType,pExpList->resID);
AddMyResource_((Handle)pExpList->hExpandList,kExpandListType,pExpList->resID,"");
if (!(err=ResError())) MyUpdateResFile(SettingsRefN);
DetachResource((Handle)pExpList->hExpandList);
}
ZapHandle((Handle)pExpList->hExpandList);
}
/************************************************************************
* AddMailboxListItems - add mailboxes to list
************************************************************************/
void AddMailboxListItems(ViewListPtr pView, short nodeId,ExpandInfoPtr pExpList)
{
short i,n;
Point c;
short menuID;
VLNodeInfo info;
Str255 sTemp;
MenuHandle mh;
Boolean haveIMAP;
Boolean doingTopLvlIMAP=false;
haveIMAP = IMAPExists();
mh = GetMenuHandle(nodeId==0 || nodeId == kEudoraFolder ? MAILBOX_MENU : nodeId);
n = CountMenuItems(mh);
c.h = 0;
SetPort_(GetMyWindowCGrafPtr(pView->wPtr));
menuID = GetMenuID(mh);
i = (menuID==MAILBOX_MENU) ? 1: MAILBOX_FIRST_USER_ITEM-MAILBOX_BAR1_ITEM;
if (nodeId==0)
{
// First level. Add Eudora folder
if (haveIMAP)
{
info.useLevelZero = false;
info.isParent = true;
}
else
{
info.useLevelZero = true;
info.isParent = false;
}
info.iconID = APP_ICON;
info.nodeID = kEudoraFolder;
info.isCollapsed = !FindExpandDirID(MailRoot.dirId,pExpList);
info.style = 0;
if (haveIMAP)
{
// Any unread in the local mailboxes?
short count = CountMenuItems(mh);
short item;
for(item=1;item<=count;item++)
{
Style style;
GetMenuItemText(mh, item, sTemp);
if (!IsIMAPCacheName(sTemp))
{
GetItemStyle(mh,item,&style);
if (style & UnreadStyle)
{
info.style = UnreadStyle;
break;
}
}
}
}
info.refCon = MailRoot.dirId;
GetMBDirName(Root.vRef,Root.dirId,info.name); // Name of Mail Folder
LVAdd(pView, &info);
// If we have IMAP folders, add them at this level.
// Otherwise add all the POP stuff at this level
if (haveIMAP)
{
for (i=MAILBOX_FIRST_USER_ITEM;i<=n;i++)
{
MyGetItem(mh,i,info.name);
if (StringSame(info.name,"\p-")) break; // stop at menu divider
}
i++;
doingTopLvlIMAP = true;
}
}
info.useLevelZero = false;
for (;i<=n;i++)
{
short mailBoxIcon;
Style style;
mailBoxIcon = kMailBoxIcon;
if (menuID==MAILBOX_MENU)
{
switch (i)
{
case MAILBOX_IN_ITEM: // In box
mailBoxIcon = IN_MB_ICON;
break;
case MAILBOX_OUT_ITEM: // Out box
mailBoxIcon = OUT_MB_ICON;
break;
case MAILBOX_JUNK_ITEM: // Junk box
//mailBoxIcon = JUNK_MB_ICON;
break;
case MAILBOX_TRASH_ITEM: // Trash
mailBoxIcon = kTrashBoxIcon;
break;
case MAILBOX_BAR1_ITEM:
i = MAILBOX_FIRST_USER_ITEM;
break;
}
}
if (i <= n)
{
short vRef;
long dirID;
MyGetItem(mh,i,info.name);
if (menuID==MAILBOX_MENU && haveIMAP && StringSame(info.name,"\p-")) break; // stop at menu divider
info.nodeID = menuID;
if (info.isParent = HasSubmenu(mh,i))
{
short thisMenuID;
thisMenuID = SubmenuId(mh,i);
MBMenuToFile(thisMenuID, &vRef, &dirID);
info.iconID = kFolderIcon;
info.isCollapsed = info.isParent && !FindExpandDirID(dirID,pExpList);
info.refCon = dirID;
}
else
{
info.iconID = mailBoxIcon;
info.isCollapsed = false;
}
if (doingTopLvlIMAP)
{
info.nodeID = kIMAPFolder;
info.iconID = APP_ICON;
}
else if (IsIMAPBox(&info))
info.iconID = IMAPMailboxIcon(&info, menuID);
if (info.iconID == kMailBoxIcon && !PrefIsSet(PREF_NO_CUSTOM_MB_ICONS))
{
Handle resH;
OSType junk;
// See if we have a custom icon
SetResLoad(false);
resH = GetNamedResource('ICN#',info.name);
SetResLoad(true);
if (resH)
{
short resFile = HomeResFile(resH);
// Don't use icons from Eudora application or help file
if (resFile != AppResFile && resFile != HelpResFile)
GetResInfo(resH,&info.iconID,&junk,sTemp);
}
}
GetItemStyle(mh,i,&style);
info.style = style&UnreadStyle ? UnreadStyle : 0;
LVAdd(pView, &info);
}
}
}
/************************************************************************
* IMAPMailboxIcon - which icon should be used for this IMAP mailbox?
************************************************************************/
long IMAPMailboxIcon(VLNodeInfo *info, short menuID)
{
long id = kMailBoxIcon;
short vRef;
long dirID;
FSSpec mailboxSpec;
MailboxNodeHandle node = nil;
PersHandle pers = nil;
Str255 sTemp;
MBMenuToFile(menuID,&vRef,&dirID);
if (IsIMAPVD(vRef,dirID))
{
SimpleMakeFSSpec(vRef, dirID, info->name, &mailboxSpec);
mailboxSpec.parID = SpecDirId(&mailboxSpec);
LocateNodeBySpecInAllPersTrees(&mailboxSpec, &node, &pers);
if (node)
{
if (StringSame(info->name,GetRString(sTemp,IMAP_INBOX_NAME)) && !((*node)->childList)) // if this is the IMAP Inbox, and it can't have any children, use "In" icon
id = IN_MB_ICON;
else if (((*node)->attributes&LATT_TRASH) != 0) // if this is the trash mailbox, use the trash icon
id = kTrashBoxIcon;
else if (DoesIMAPMailboxNeed(node,kNeedsPoll)) // a polled mailbox
{
if ((*node)->childList)
id = kIMAPPolledFolderIcon; // with children
else
id = kIMAPPolledMailboxIcon; // without
}
else if (((*node)->attributes & LATT_NOSELECT)) // a strict folder
id = kFolderIcon;
else if ((*node)->childList) // a regular IMAP mailbox folder
id = kIMAPMailboxIcon;
}
}
return (id);
}
/************************************************************************
* WhichTree - which tree (POP, IMAP account) does this file/folder belong to
************************************************************************/
static short WhichTree(VLNodeInfo *pInfo)
{
MailboxNodeHandle node;
PersHandle pers;
FSSpec spec;
if (IMAPExists())
{
MakeMBSpec(pInfo,&spec);
if (IsIMAPBox(pInfo))
{
spec.parID = SpecDirId(&spec);
LocateNodeBySpecInAllPersTrees(&spec, &node, &pers);
return (long)pers;
}
}
// POP mailbox
return -1;
}
/************************************************************************
* MailboxesLVCallBack - callback function for List View
************************************************************************/
long MailboxesLVCallBack(ViewListPtr pView, VLCallbackMessage message, long data)
{
OSErr err = noErr;
SendDragDataInfo *pSendData;
MBDragData dragData;
VLNodeInfo *pInfo;
MenuHandle mh;
short nodeID;
switch (message)
{
case kLVAddNodeItems:
AddMailboxListItems(pView,data,&gExpandList);
break;
case kLVGetParentID:
if (((VLNodeInfo *)data)->rowNum==1)
return kEudoraFolder;
nodeID = ((VLNodeInfo *)data)->nodeID;
if (nodeID == kEudoraFolder || nodeID == kIMAPFolder) nodeID = MAILBOX_MENU;
return MBGetFolderMenuID(nodeID,((VLNodeInfo *)data)->name);
//break;
case kLVOpenItem:
MBListOpen(&MB.list);
break;
case kLVMoveItem:
MBMove((VLNodeInfo*)data);
break;
case kLVDeleteItem:
MBRemove();
break;
case kLVRenameItem:
MBRename((StringPtr)data);
break;
case kLVQueryItem:
pInfo = ( VLNodeInfo *)data;
switch (pInfo->query)
{
case kQuerySelect:
return true;;
case kQueryDrag:
{
// make sure we're not dragging items from different trees
// must be all POP or same IMAP tree
long thisTree = WhichTree(pInfo);
if (!pView->dragGroup)
pView->dragGroup = thisTree; // this is the first item we've seen
else if (pView->dragGroup != thisTree)
return false; // drag to different tree
}
// fall through to common rename code
case kQueryRename:
if ((((VLNodeInfo*)data)->nodeID == kIMAPFolder)
|| (IsIMAPBox(pInfo) && !CanModifyMailboxTrees())) return (false);
return (!IsSpecialBox(pView,pInfo));
case kQueryDrop:
case kQueryDropParent:
// make sure we're not dragging items from different trees
// must be all POP or same IMAP tree
if (gfBoxDrag && pView->dragGroup != WhichTree(pInfo))
return false; // drag to different tree
// IMAP drop cases
if (IsIMAPBox(pInfo))
{
IMAPMailboxAttributes att;
FSSpec toSpec;
// can't drop if we can't currently modify mailbox trees
if (gfBoxDrag && !CanModifyMailboxTrees()) return (false);
MBMenuToFile(pInfo->nodeID, &(toSpec.vRefNum), &(toSpec.parID));
PCopy(toSpec.name, pInfo->name);
toSpec.parID = SpecDirId(&toSpec);
// can't drop if the destination can't have messages
if (MailboxAttributes(&toSpec, &att))
{
if ((gfMessageDrag && att.noSelect) || // Will MB accept messages?
gfBoxDrag && att.noInferiors) // Will MB accept children?
return false;
else
return true;
}
}
if (pInfo->query==kQueryDrop)
{
if (pInfo->isParent || pInfo->rowNum == kItemEudoraFolder)
// Can accept mail box drags
return gfBoxDrag;
else
// Can accept message drags
return gfMessageDrag;
}
else
// message==kQueryDropParent
return gfBoxDrag;
break;
case kQueryDragExpand:
// if we're dragging to a different tree, don't auto-expand
// folders
if (gfBoxDrag && pView->dragGroup != WhichTree(pInfo))
return false; // drag to different tree
return true;
case kQueryDCOpens:
// If IMAP mailbox hybrid, double-click opens the mailbox
// instead of expanding/collapsing the folder
return pInfo->iconID == kIMAPMailboxIcon || IsIMAPTrashBox(pInfo) || (!pInfo->isParent && pInfo->nodeID != kEudoraFolder);
}
break;
case kLVCopyItem:
break;
case kLVExpandCollapseItem:
if (((VLNodeInfo *)data)->rowNum==1 && (MainEvent.modifiers & optionKey))
{
FinderOpen(&SettingsSpec,true,false);
}
else
SaveExpandStatus((VLNodeInfo *)data,&gExpandList);
break;
case kLVSendDragData:
pSendData = (SendDragDataInfo *)data;
PCopy(dragData.name,pSendData->info->name);
dragData.menuID = pSendData->info->nodeID;
if (mh = GetMenuHandle(dragData.menuID))
dragData.menuItem = FindItemByName(mh,dragData.name);
MakeMBSpec(pSendData->info,&dragData.spec);
err = SetDragItemFlavorData(pSendData->drag, pSendData->itemRef, pSendData->flavor,&dragData, sizeof(dragData), 0L);
break;
}
return err;
}
/************************************************************************
* MakeMBSpec - make a file spec for a mailbox file
************************************************************************/
void MakeMBSpec(VLNodeInfo *pData,FSSpec *pSpec)
{
short vRef;
long dirID;
Str32 name;
MBMenuToFile(pData->nodeID, &vRef, &dirID);
PCopy(name,pData->name);
if (pData->nodeID == MAILBOX_MENU)
switch(pData->rowNum)
{
// Filename may be different than name in list if localized
case kItemInBox: GetRString(name,IN); break;
case kItemOutBox: GetRString(name,OUT); break;
case kItemJunkBox: GetRString(name,JUNK); break;
case kItemTrash: GetRString(name,TRASH); break;
}
FSMakeFSSpec(vRef,dirID,name,pSpec);
}
/************************************************************************
* IsIMAPBox - does this entry refer to an IMAP mailbox?
************************************************************************/
Boolean IsIMAPBox(VLNodeInfo *pData)
{
short vRef;
long dirID;
if (pData->nodeID == kIMAPFolder)
return true;
MBMenuToFile(pData->nodeID, &vRef, &dirID);
return IsIMAPVD(vRef,dirID);
}
/**********************************************************************
* OpenMBFolder - open folders above this one in the mailbox list
**********************************************************************/
void OpenMBFolder(ViewListPtr pView,short menuID,StringPtr s)
{
MenuHandle mh;
if (menuID>0 && (mh = GetMenuHandle(menuID)))
{
short item;
if (menuID == MAILBOX_MENU)
{
if (IMAPExists())
{
// Open Eudora Folder
Str32 s;
GetDirName(nil,Root.vRef,Root.dirId,s);
LVExpand(pView,kEudoraFolder,s,true);
}
}
else
{
MenuHandle mhPar = ParentMailboxMenu(mh,&item);
if (IMAPExists() && GetMenuID(mhPar) == MAILBOX_MENU)
{
short vRef;
long dirID;
MBMenuToFile(GetMenuID(mh), &vRef, &dirID);
if (IsIMAPVD(vRef,dirID))
{
// This is an IMAP account folder
GetMenuTitle(mh,s);
LVExpand(pView,kIMAPFolder,s,true);
return;
}
}
OpenMBFolder(pView,GetMenuID(mhPar),s);
MyGetItem(mhPar,item,s);
LVExpand(pView,GetMenuID(mhPar),s,true);
}
}
}
/**********************************************************************
* MBIdle - MB idle function
**********************************************************************/
static void MBIdle(MyWindowPtr win)
{
EnableIMAPButtons(win);
}
/**********************************************************************
* MBIdle - see if we need to hide/show the IMAP refresh button
**********************************************************************/
static void EnableIMAPButtons(MyWindowPtr win)
{
Boolean haveIMAP = IMAPExists();
MenuHandle mh = nil;
if (MB.IMAPButtonsVisible != haveIMAP)
{
SetControlVisibility(CtlOptionsMenu,haveIMAP,true);
#ifdef SHOW_RESYNC_BUTTON
SetControlVisibility(CtlResync,haveIMAP,true);
#endif
MB.IMAPButtonsVisible = haveIMAP;
}
#ifdef SHOW_RESYNC_BUTTON
if (MB.IMAPButtonsVisible)
{
// also grey out the Resync control if there's nothing selected
if ( MB.imapMailboxSelected != MB.resyncEnabled)
{
MB.resyncEnabled = MB.imapMailboxSelected;
SetGreyControl(CtlResync, !MB.imapMailboxSelected);
}
}
#endif
}
/**********************************************************************
* EnableOptionsMenu - properly enable and disable items in the options
* menu based on what's selected in the mailboxes window
**********************************************************************/
void EnableOptionsMenu(MyWindowPtr win, Boolean optionPressed)
{
Boolean enabled;
MenuHandle mh = nil;
short count,i;
VLNodeInfo data;
Boolean imapMailboxSelected = false;
Boolean imapPersSelected = false;
Boolean popMailboxSelected = false;
if (MB.IMAPButtonsVisible)
{
// what is visible?
if (count = LVCountSelection(&MB.list))
{
for (i=1;i<=count;i++)
{
// get mailbox spec
MBGetData(&data,i);
if (data.nodeID == kIMAPFolder)
imapPersSelected = true;
else if (IsIMAPBox(&data))
imapMailboxSelected = true;
else if (data.nodeID == kEudoraFolder)
;
else if (data.iconID == kFolderIcon)
;
else
popMailboxSelected = true;
}
}
// properly enable the menu items
if (!GetControlData(CtlOptionsMenu,kControlMenuPart,kControlBevelButtonMenuHandleTag,sizeof(mh),(Ptr)&mh,nil) && mh)
{
// prevent the user from doing a refresh if there's currently a background thread running.
enabled = CanModifyMailboxTrees() && (imapMailboxSelected || imapPersSelected || (CurrentModifiers()&optionKey));
EnableIf(mh, OPTIONS_REFRESH_ITEM, enabled);
// properly enable all IMAP-mailbox-specifc items while we're at it
enabled = imapMailboxSelected;
EnableIf(mh, OPTIONS_RESYNC_ITEM, enabled);
EnableIf(mh, OPTIONS_RESYNCSUB_ITEM, enabled);
EnableIf(mh, OPTIONS_AUTOSYNC_ITEM, enabled);
EnableIf(mh, OPTIONS_SHOWDELETED_ITEM, enabled);
EnableIf(mh, OPTIONS_EXPUNGE_ITEM, enabled);
// set the check marks appropriately
SetItemMark (mh, OPTIONS_AUTOSYNC_ITEM, IMAPOptionsCheckMarkChar(kNeedsPoll));
SetItemMark (mh, OPTIONS_SHOWDELETED_ITEM, IMAPOptionsCheckMarkChar(kShowDeleted));
// Compact menu item applies to POP mailboxes, too
EnableIf(mh, OPTIONS_COMPACT_ITEM, (popMailboxSelected || imapMailboxSelected));
}
}
}
/**********************************************************************
* IsSpecialBox - see if this is a special POP box (in, out, trash, Eudora folder)
**********************************************************************/
static Boolean IsSpecialBox(ViewListPtr pView, VLNodeInfo *pInfo)
{
VLNodeInfo efInfo;
if (pInfo->rowNum >= kItemMailBoxes) return false;
// Need to get status of Eudora folder
LVGetItem(pView,1,&efInfo,false);
if (efInfo.isParent && efInfo.isCollapsed)
return pInfo->rowNum <= 1;
else
return (pInfo->rowNum < kItemMailBoxes);
}
/**********************************************************************
* MBFindInCollapsed - search a collapsed folder
**********************************************************************/
Boolean MBFindInCollapsed(MyWindowPtr win,ViewListPtr pView,PStr what,short menuID)
{
CGrafPtr winPort;
MenuHandle mh;
short item,count,id;
Str255 s,name;
if (mh = GetMenuHandle(menuID))
{
count = CountMenuItems(mh);
for (item=1;item<=count;item++)
{
if (id = SubmenuId(mh,item))
{
// has submenu. recurse
if (MBFindInCollapsed(win,pView,what,id))
return true;
}
MyGetItem(mh,item,name);
if (FindStrStr(what,name)>=0)
{
// found
// open collapsed folder(s) and select item
OpenMBFolder(pView,menuID,s);
LVSelect(pView,menuID,name,false);
winPort = GetMyWindowCGrafPtr (win);
LVDraw(pView,MyGetPortVisibleRegion(winPort),true,false);
return true;
}
}
}
return false;
}
/**********************************************************************
* IsIMAPTrashBox - is this an IMAP trash mailbox?
**********************************************************************/
Boolean IsIMAPTrashBox(VLNodeInfo *data)
{
return (data->iconID == kTrashBoxIcon && IsIMAPBox(data));
}
/************************************************************************
* IMAPOptionsCheckMarkChar - return the appropriate character to display
* next to an IMAP mailboxes options menu item
************************************************************************/
char IMAPOptionsCheckMarkChar(MailboxNeedsEnum needs)
{
char c = 0;
short count, i, needsMark;
VLNodeInfo data;
FSSpec spec;
MailboxNodeHandle mbox;
PersHandle pers;
if (count = LVCountSelection(&MB.list))
{
// count the number of mailboxes that need to be marked
needsMark = 0;
for (i=1;i<=count;i++)
{
// get mailbox spec
MBGetData(&data,i);
MakeMBSpec(&data,&spec);
// is this an IMAP mailbox?
if (IsIMAPBox(&data))
{
spec.parID = SpecDirId(&spec);
LocateNodeBySpecInAllPersTrees(&spec, &mbox, &pers);
if (pers && mbox && (DoesIMAPMailboxNeed(mbox,needs) || ((needs == kNeedsPoll) && (mbox == LocateInboxForPers(pers)))))
needsMark++;
}
}
// return the proper char
if (needsMark)
{
if (count == needsMark)
c = checkMark;
else
c = dashChar;
}
}
return (c);
}
/************************************************************************
* MBRefreshIMAPMailboxes - refresh IMAP mailbox trees. That is, fetch
* the mailbox list from the server and adjust cache mailboxes as needed
************************************************************************/
void MBRefreshIMAPMailboxes(Boolean optionPressed)
{
Boolean refresh = false;
short count, i;
VLNodeInfo data;
FSSpec spec;
PersHandle pers = nil;
MailboxNodeHandle node = nil;
// is there anything selected that can be refreshed?
if (!optionPressed && (count = LVCountSelection(&MB.list)))
{
for (i=1;i<=count;i++)
{
// get mailbox spec
MBGetData(&data,i);
MakeMBSpec(&data,&spec);
// who does this mailbox belong to?
if (data.nodeID == kIMAPFolder)
{
// an IMAP personality heading is selected. Which personality does it refer to?
pers = FindPersByName(spec.name);
}
else
{
// a mailbox is selected. Who does it belong to?
spec.parID = SpecDirId(&spec);
LocateNodeBySpecInAllPersTrees(&spec, &node, &pers);
}
// if it belongs to an IMAP personality, we'll want to refresh this personality
if (pers)
{
(*pers)->imapRefresh = 1;
refresh = true;
}
}
// now go refresh
if (refresh) IMAPRefreshPersCaches();
}
else if (optionPressed)
{
// Shift was pressed. Refresh ALL the IMAP personalities
IMAPRefreshAllCaches();
}
}
/************************************************************************
* MBResyncOrExpungeIMAPMailboxes - process the selected IMAP mailboxes.
************************************************************************/
OSErr MBResyncOrExpungeIMAPMailboxes(Boolean optionPressed, TaskKindEnum task)
{
OSErr err;
Handle mailboxes;
// Build a handle of all of the selected mailboxes
err = GetSelectedMailboxSpecs(&mailboxes, optionPressed);
if ((err == noErr) && mailboxes)
{
// process the mailboxs
err = IMAPProcessMailboxes(mailboxes, task);
}
if (err != noErr)
{
WarnUser(MEM_ERR, err);
ZapHandle(mailboxes);
}
return (err);
}
/************************************************************************
* MBMarkIMAPMailboxes - mark selected mailboxes
************************************************************************/
void MBMarkIMAPMailboxes(Boolean on, MailboxNeedsEnum needs)
{
short count, i;
VLNodeInfo data;
FSSpec spec;
PersHandle pers = nil;
MailboxNodeHandle node = nil;
if (count = LVCountSelection(&MB.list))
{
for (i=1;i<=count;i++)
{
// get mailbox spec
MBGetData(&data,i);
MakeMBSpec(&data,&spec);
if (data.nodeID != kIMAPFolder)
{
// a mailbox is selected. Who does it belong to?
spec.parID = SpecDirId(&spec);
LocateNodeBySpecInAllPersTrees(&spec, &node, &pers);
if (node)
{
// is this not the inbox?
if ((needs != kNeedsPoll) || (node != LocateInboxForPers(pers)))
{
// set the property
SetIMAPMailboxNeeds(node, needs, on);
// are we hiding or showing deleted messages?
if (needs == kShowDeleted)
HideDeletedMessages(node, true, on);
// update the cache mailbox now
WriteIMAPMailboxInfo(&spec, node);
}
}
}
}
// update the list
MBTickle(nil,nil);
}
}
/************************************************************************
* MBCompactMailboxes - compact selected mailboxes
************************************************************************/
void MBCompactMailboxes(void)
{
short count, i;
VLNodeInfo data;
FSSpec spec;
PersHandle pers = nil;
MailboxNodeHandle node = nil;
// properly set autocheck property
if (count = LVCountSelection(&MB.list))
{
for (i=1;(i<=count) && !CommandPeriod;i++)
{
// get mailbox spec
MBGetData(&data,i);
MakeMBSpec(&data,&spec);
// compact the mailbox
if ((data.nodeID != kIMAPFolder) && (data.nodeID != kEudoraFolder))
{
// is this an IMAP mailbox?
if (IsIMAPBox(&data))
spec.parID = SpecDirId(&spec);
// is this a POP folder?
else if (FSpIsItAFolder(&spec))
continue;
CompactMailbox(&spec,false);
}
}
// update the list
MBTickle(nil,nil);
}
}