eudora-mac/import.c

1 line
59 KiB
C
Executable File
Raw Permalink Blame History

/* 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. */
/* Copyright (c) 2000 by QUALCOMM Incorporated */
#define FILE_NUM 132
// routines to import mail from other applications
#include "import.h"
#pragma segment Importer
// these are the things OE can import
enum
{
kISettings = 0,
kIMessages,
kIAddresses,
kISignatures,
kILimit
};
// these are the items in the importer selection dialog
enum
{
kISOKButton = 1,
kISCancelButton = 2,
kISImporterPopup = 3
};
// these are the items in the import what dialog
enum
{
kIWOKButton = 1,
kIWCancelButton = 2,
kIWSettingsCheckbox = 3,
kIWMessagesCheckbox = 4,
kIWAddressesCheckbox = 5,
kIWSignaturesCheckbox = 6
};
/* Structure to hold data about what the user wants to import */
typedef struct
{
Boolean importWhat[kILimit];
} ImportWhatStruct, *ImportWhatPtr;
#define MAX_MAILBOX_NAME_LENGTH 27
#define MAX_PROGRESS_LEN 33
static LineIOP Lip;
static long gImportMsgEnd;
OSErr ImportErr;
/************************************************************************
* Importer prototypes
************************************************************************/
// Open the importer window
static void OpenImportWindow(long pluginId, Boolean reopen);
// Is the import window open?
static Boolean IsImportWindowOpen(void);
// ask the user to select an importer plugin
Boolean ImportSelectPlugin(long *id);
// Import from the selected account
OSErr ImportAccount(ImportAccountInfoP account);
// Determine what that stuff is
Boolean ImportWhat(ImportAccountInfoP account, ImportWhatPtr what);
// Import mail from the selected account
OSErr ImportMail(ImportAccountInfoP account);
// import settings from an email account
OSErr ImportSettings(ImportAccountInfoP account);
Boolean PersDataIsGood(ImportPersDataP persD);
void AddNewPersonality(ImportPersDataP persD);
// import signatures from another email app
OSErr ImportSignatures(ImportAccountInfoP account);
// import contact information from another email app
OSErr ImportAddresses(ImportAccountInfoP account);
extern Boolean SaveIndNickFile(short which,Boolean saveChangeBits);
// read data from a file
OSErr ImportRecvLine(TransStream stream, UPtr buffer, long *size);
// Cleanup
void ZapImportablesHandle(ImportAccountInfoH *importables);
extern void GenAliasList(void);
/************************************************************************
* DoMailImport - allow the user to select which application to import
* from, and display the import window.
************************************************************************/
void DoMailImport(void)
{
long id = kUnspecifiedImportPluginId;
// ask the user to select an applicaiton to import from
if (ImportSelectPlugin(&id))
{
// display list of importable accounts
OpenImportWindow(id, IsImportWindowOpen());
}
}
/************************************************************************
* ImportSelectPlugin - ask the user from what application to import
************************************************************************/
Boolean ImportSelectPlugin(long *id)
{
MyWindowPtr dgPtrWin;
DialogPtr dgPtr;
short item, i;
extern ModalFilterUPP DlgFilterUPP;
ControlHandle ip = nil;
MenuHandle mh = nil;
ImportAccountInfoH importables;
short numImporters;
*id = kUnspecifiedImportPluginId;
//
// first, see what importers are around
//
// ask the importers what they can import ...
importables = NuHandle(0L);
if ((MemError()!=noErr) || !importables || !*importables)
{
ImportError(kUnspecifiedImportPluginId, kImportSetupErr, kImportMemError, MemError(), __LINE__);
return(false);
}
ETLQueryImporters(&importables, kUnspecifiedImportPluginId, false);
numImporters = GetHandleSize(importables)/sizeof(ImportAccountInfoS);
if (numImporters <= 1)
{
// only one importer installed. Use it.
*id = 0;
ZapImportablesHandle(&importables);
return (true);
}
//
// get the select dialog
//
if ((dgPtrWin = GetNewMyDialog(IMPORTER_SELECT_DLOG,nil,nil,InFront))==nil)
{
ImportError(kUnspecifiedImportPluginId, kImportSetupErr, kImportMemError, MemError(), __LINE__);
return(false);
}
dgPtr = GetMyWindowDialogPtr(dgPtrWin);
//
// Build the list of importers
//
ip = GetDItemCtl (dgPtr, kISImporterPopup);
if (ip) mh = GetControlPopupMenuHandle (ip);
if (!mh)
{
ImportError(kUnspecifiedImportPluginId, kImportSetupErr, kImportMemError, MemError(), __LINE__);
return(false);
}
// add the things the importer can import to the popup menu ...
i = GetHandleSize(importables)/sizeof(ImportAccountInfoS);
while (i)
{
MyInsMenuItem(mh, (*importables)[i-1].appName, 0);
i--;
}
// setup the popup menu control ...
SetControlMaximum(ip, numImporters+1);
SetControlMinimum(ip, 1);
SetDItemState (dgPtr, kISImporterPopup, 1);
//
// Prepare the dialog for display
//
// Fix the controls
SetPort(GetDialogPort(dgPtr));
ConfigFontSetup(dgPtrWin);
ReplaceAllControls(dgPtr);
// Highlite the OK button
HiliteButtonOne(dgPtr);
// display it
StartMovableModal(dgPtr);
ShowWindow(GetDialogWindow(dgPtr));
//
// Do the dialog
//
do
{
MovableModalDialog(dgPtr,DlgFilterUPP,&item);
}
while ((item!=kIWOKButton) && (item!=kIWCancelButton));
// Remember what the user chose
if (GetControlValue(ip) <= numImporters)
*id = (*importables)[GetControlValue(ip) - 1].id;
EndMovableModal(dgPtr);
DisposeDialog(dgPtr);
ZapImportablesHandle(&importables);
return (item==kISOKButton);
}
/************************************************************************
* ImportAccount - Import data from a mailstore
************************************************************************/
OSErr ImportAccount(ImportAccountInfoP account)
{
OSErr err = noErr, importErr = noErr;
ImportWhatStruct what;
if (ImportWhat(account, &what))
{
// import settings
if (what.importWhat[kISettings])
{
err = ImportSettings(account);
if (importErr == noErr) importErr = err;
}
// import mail
if ((err != memFullErr) && what.importWhat[kIMessages])
{
err = ImportMail(account);
if (importErr == noErr) importErr = err;
}
// import addresses
if ((err != memFullErr) && what.importWhat[kIAddresses])
{
err = ImportAddresses(account);
if (importErr == noErr) importErr = err;
}
// import signatures
if ((err != memFullErr) && what.importWhat[kISignatures])
{
err = ImportSignatures(account);
if (importErr == noErr) importErr = err;
}
CloseProgress();
// let the user know we finished importing
if (importErr == noErr)
{
if (IsFreeMode() && (what.importWhat[kISettings] || what.importWhat[kISignatures]))
{
// we just imported some things the user won't have immediate access to.
if(ComposeStdAlert(kAlertCautionAlert, LIGHT_IMPORT_COMPLETE)==1) NewClientModePlusOne = 1;
}
else
{
// All is well with the world.
ComposeStdAlert(kAlertNoteAlert, IMPORT_COMPLETE);
}
}
else
{
// warn the user something went wrong during import.
ComposeStdAlert(kAlertStopAlert, IMPORT_INCOMPLETE);
}
}
return (importErr);
}
/************************************************************************
* ImportWhat - ask the user what sorts of things to import
************************************************************************/
Boolean ImportWhat(ImportAccountInfoP account, ImportWhatPtr what)
{
MyWindowPtr dgPtrWin;
DialogPtr dgPtr;
short item;
extern ModalFilterUPP DlgFilterUPP;
Zero(*what);
// get the what dialog
if ((dgPtrWin = GetNewMyDialog(IMPORT_WHAT_DLOG,nil,nil,InFront))==nil)
{
ImportError(kUnspecifiedImportPluginId, kImportSetupErr, kImportMemError, MemError(), __LINE__);
return(false);
}
dgPtr = GetMyWindowDialogPtr (dgPtrWin);
//fix the controls
SetPort(GetDialogPort(dgPtr));
ConfigFontSetup(dgPtrWin);
ReplaceAllControls(dgPtr);
// Highlite the OK button
HiliteButtonOne(dgPtr);
// Check the checkboxes
for (item = kIWSettingsCheckbox; item <= kIWSignaturesCheckbox; item++)
SetDItemState(dgPtr,item,!GetDItemState(dgPtr,item));
// display it
MyParamText(account->accountName,"","","");
StartMovableModal(dgPtr);
ShowWindow(GetDialogWindow(dgPtr));
do
{
MovableModalDialog(dgPtr,DlgFilterUPP,&item);
if ((item>=kIWSettingsCheckbox) && (item<=kIWSignaturesCheckbox))
SetDItemState(dgPtr,item,!GetDItemState(dgPtr,item));
}
while ((item!=kIWOKButton) && (item!=kIWCancelButton));
// remember what the user has checked
what->importWhat[kISettings] = GetDItemState(dgPtr,kIWSettingsCheckbox);
what->importWhat[kIMessages] = GetDItemState(dgPtr,kIWMessagesCheckbox);
what->importWhat[kIAddresses] = GetDItemState(dgPtr,kIWAddressesCheckbox);
what->importWhat[kISignatures] = GetDItemState(dgPtr,kIWSignaturesCheckbox);
EndMovableModal(dgPtr);
DisposeDialog(dgPtr);
return(item==kIWOKButton);
}
/************************************************************************
* ImportMail - Import an account's mailboxes and messages
************************************************************************/
OSErr ImportMail(ImportAccountInfoP account)
{
OSErr err = noErr;
Str255 progress;
// display some progress telling the user we're importing messages
OpenProgress();
ProgressMessageR(kpTitle,IMPORT_PROGRESS_TITLE);
ComposeRString(progress, IMPORT_MESSAGE_PROGRESS_SUBTITLE, account->accountName);
if (progress[0] > MAX_PROGRESS_LEN)
{
progress[0] = MAX_PROGRESS_LEN;
progress[MAX_PROGRESS_LEN] = '<EFBFBD>';
}
ProgressMessage(kpSubTitle,progress);
err = ETLImportMail(account);
if (err != noErr)
{
// an error occurred importing mail
ImportError(account->id, kImportMessagesErr, kImportMessagesError, err, __LINE__);
}
return (err);
}
/************************************************************************
* ImportMakeMailboxCallback - callback that handles new mailbox creation
************************************************************************/
OSErr ImportMakeMailboxCallback(ImportMailboxOperationEnum command, FSSpecPtr boxSpec, Boolean isFolder, Boolean noSelect)
{
OSErr err = noErr;
FSSpec newFolder;
TOCHandle tocH = nil;
switch (command)
{
// importing mailboxes is about to begin
case EMS_IMPORT_MAILBOX_Start:
{
// create a location for new mailboxes
SimpleMakeFSSpec(MailRoot.vRef, MailRoot.dirId, boxSpec->name, boxSpec);
UniqueSpec(boxSpec, MAX_MAILBOX_NAME_LENGTH);
if (BadMailboxName(boxSpec, true)) err = dupFNErr;
break;
}
case EMS_IMPORT_MAILBOX_Create_Mailbox:
{
// make sure the mailbox has a unique name
UniqueSpec(boxSpec, MAX_MAILBOX_NAME_LENGTH);
// are we creating a folder?
if (isFolder)
{
// make the folder
newFolder = *boxSpec;
BadMailboxName(&newFolder, true);
}
// are we creating something that can hold messages?
if (!noSelect)
{
// put it nside the folder if we create the folder, too.
if (isFolder) boxSpec->parID = newFolder.parID;
if (BadMailboxName(boxSpec, false))
err = fnfErr;
}
break;
}
// we're done importing messages into this mailbox
case EMS_IMPORT_MAILBOX_Flush_Mailbox:
{
// Flush it.
if (boxSpec)
{
tocH = FindTOC(boxSpec);
if (tocH) BoxFClose(tocH,true);
}
}
// mailbox creation is done
case EMS_IMPORT_MAILBOX_Done:
{
// let the menus and mailboxes window know about it
BuildBoxMenus();
MBTickle(nil,nil);
break;
}
default:
break;
}
return (err);
}
/************************************************************************
* CreateOutgoingMessage - create an outgoing message in the right place
************************************************************************/
OSErr ImportMakeOutMessCallback(emsMakeOutMessDataP o)
{
OSErr err = noErr;
FSSpec toSpec = o->boxSpec;
MyWindowPtr win; // the imported message
MessHandle messH;
Str255 html, scratch;
char *scan;
Boolean isHtml = false;
short i;
FSSpecPtr attach;
TOCHandle tocH = nil;
SignedByte state;
short amount;
//
// Make a new outgoing message
//
if (win=DoComposeNew(nil))
{
messH = Win2MessH(win);
// To:
SetMessText(messH,TO_HEAD,LDRef(o->toAddresses),GetHandleSize(o->toAddresses));
UL(o->toAddresses);
// From:
SetMessText(messH,FROM_HEAD,o->fromAddress+1,o->fromAddress[0]);
// Subject:
SetMessText(messH,SUBJ_HEAD,o->subject+1,o->subject[0]);
// Cc:
if (o->ccAddresses)
{
SetMessText(messH,CC_HEAD,LDRef(o->ccAddresses),GetHandleSize(o->ccAddresses));
UL(o->ccAddresses);
}
// Bcc:
if (o->bccAddresses)
{
SetMessText(messH,BCC_HEAD,LDRef(o->bccAddresses),GetHandleSize(o->bccAddresses));
UL(o->bccAddresses);
}
// add the attachments
for (i = 0; i < o->numAttachments; i++)
{
if (GetHandleSize(o->attachSpecs) >= (o->numAttachments*sizeof(FSSpec)))
{
attach = &((FSSpec *)*(o->attachSpecs))[i];
CompAttachSpec(win, attach);
}
}
// baa baa black sheep have you any wool?
if (o->text && *(o->text) && GetHandleSize(o->text))
{
// Set the HTML flag if the first bit of the message contains the HTML string
Zero(html);
GetRString(html,HTMLTagsStrn+htmlTag);
amount = MIN(255, GetHandleSize(o->text));
BlockMove(*o->text, scratch, amount);
scan = scratch;
while (*scan && (scan <= (scratch+amount )))
{
if (*scan == '<')
{
if (!striscmp(scan+1, html+1))
{
isHtml = true;
TurnIntoEudoraHTML(&o->text);
break;
}
}
scan++;
}
}
// The body of the message
PETEInsertTextHandle(PETE,TheBody,PeteLen(TheBody),o->text,GetHandleSize(o->text),0,nil);
// mark the message as sent if it's in the Sent Items folder
if (o->isSent)
SetState((*messH)->tocH, (*messH)->sumNum, SENT);
else
SetState((*messH)->tocH, (*messH)->sumNum, UNSENT);
//
// transfer the message into the correct place
//
MoveMessage((*messH)->tocH, (*messH)->sumNum, &toSpec, true);
DeleteSum((*messH)->tocH, (*messH)->sumNum);
CloseMyWindow(GetMyWindowWindowPtr((*messH)->win));
//
// Polish the new message
//
tocH = TOCBySpec(&toSpec);
if (tocH)
{
// set the html bit if we must
if (isHtml) (*tocH)->sums[(*tocH)->count-1].opts |= OPT_HTML;
// add the correct date, if there is one.
if (o->date)
{
(*tocH)->sums[(*tocH)->count-1].seconds = o->date - ZoneSecs();
state = HGetState(tocH);
HSetState(tocH, state);
}
}
}
else
{
// failed to create a new comp window. Memory is probably getting full.
err = memFullErr;
}
return (err);
}
/************************************************************************
* ImportRecvLine - read a line at a time from a message database
************************************************************************/
OSErr ImportRecvLine(TransStream stream, UPtr buffer, long *size)
{
static Boolean wasFrom;
static Boolean wasNl=true;
short lineType;
if (!buffer) {Boolean retVal = wasFrom; wasFrom = false; return(retVal);}
wasFrom=false;
(*size)--;
lineType = GetLine(buffer,*size,size,Lip);
if (*buffer=='\012')
{
// remove linefeed char
BlockMoveData(buffer+1,buffer,*size-1);
(*size)--;
buffer[*size] = 0;
}
if (!*size || !lineType || /*wasNl&&(wasFrom=IsFromLine(buffer)) ||*/ TellLine(Lip)>=gImportMsgEnd)
{
// signal end-of-message
*size = 2;
buffer[0]='.'; buffer[1]='\015'; buffer[2]=0;
}
else if (lineType && wasNl && *buffer=='.')
{
// insert '.' at beginning of line
BlockMoveData(buffer,buffer+1,*size);
(*size)++;
*buffer = '.';
buffer[*size] = 0;
}
wasNl = !lineType || buffer[*size-1]=='\015';
return(noErr);
}
/**********************************************************************
* ImportMessageCallback - Transfer raw MIME encoded messages
* from a file
**********************************************************************/
OSErr ImportMessageCallback(short ref, long offset, long len, short state, Handle attachments, FSSpecPtr boxSpec)
{
OSErr err = noErr;
TransVector saveCurTrans = CurTrans;
static TransVector ImportTrans = {nil,nil,nil,nil,nil,nil,nil,nil,nil,ImportRecvLine,nil};
FSSpec spec;
TOCHandle toToc = nil;
short count;
long attachLength;
ImportErr = noErr;
//
// Figure out where the message is going to go
//
toToc = TOCBySpec(boxSpec);
if (toToc == nil)
{
ImportError(kUnspecifiedImportPluginId, kImportMessagesErr, kImportMessagesError, err=fnfErr, __LINE__);
return (err);
}
//
// Now read in the actual message
//
err = BoxFOpen(toToc);
if (err == noErr)
{
GetFileByRef(ref, &spec);
if (!Lip) Lip = NuPtrClear(sizeof(*Lip));
if (!Lip)
{
err = MemError();
ImportError(kUnspecifiedImportPluginId, kImportMessagesErr, kImportMemError, err, __LINE__);
}
else
{
if ((err=FSpOpenLine(&spec,fsRdPerm,Lip))==noErr)
{
PushPers(CurPers);
// CurPers must be set to the owning personality
CurPers = PersList;
// now, grab messages
CurTrans = ImportTrans;
TOCSetDirty(toToc,true);
BadBinHex = false;
BadEncoding = 0;
if (!AttachedFiles) AttachedFiles=NuHandle(0);
SetHandleBig_(AttachedFiles,0);
SeekLine(offset,Lip);
gImportMsgEnd = offset+len;
count=FetchMessageTextLo(NULL,len,nil,0,toToc,false,true);
SetHandleBig_(AttachedFiles,0);
SaveAbomination(nil,0);
if (BadBinHex || BadEncoding) NoAttachments = true;
else NoAttachments = false;
// add on the attachment converted lines to the newly imported message
if (attachments && count)
{
for (count = 0; count < (GetHandleSize(attachments)/sizeof(FSSpec)); count++)
RecordAttachment(&((FSSpecPtr)(*attachments))[count], nil);
attachLength = GetHandleSize(AttachedFiles);
if (attachLength && ((err=WriteAttachNote((*toToc)->refN))==noErr))
{
// adjust the summary to reflect the new message length and the fact that there are attachments
(*toToc)->sums[(*toToc)->count-1].length += attachLength;
(*toToc)->sums[(*toToc)->count-1].flags |= FLAG_HAS_ATT;
}
}
PopPers();
}
if (Lip && Lip->refN)
{
CloseLine(Lip);
DisposePtr((Ptr)Lip);
Lip = nil;
}
NoAttachments = false;
CurTrans = saveCurTrans;
//
// adjust the status of the message appropriately
//
(*toToc)->sums[(*toToc)->count-1].state = state;
}
}
else
{
ImportError(kUnspecifiedImportPluginId, kImportMessagesErr, kImportMessagesError, err, __LINE__);
}
if (ImportErr) err = ImportErr;
return (err);
}
/************************************************************************
* ImportMboxCallback - Import an mbox'es worth of mail
************************************************************************/
OSErr ImportMboxCallback( FSSpecPtr sourceMBox, FSSpecPtr dest ) {
OSErr err = noErr;
TOCHandle destToc = nil;
short gotSome;
destToc = TOCBySpec ( dest );
if ( destToc == nil ) {
ImportError ( kUnspecifiedImportPluginId, kImportMessagesErr, kImportMessagesError, err=fnfErr, __LINE__ );
return err;
}
if ( noErr == ( err = BoxFOpen ( destToc ))) {
err = GetUUPCMailSpecToMailBox ( sourceMBox, fsRdPerm, destToc, &gotSome );
BoxFClose ( destToc, true );
}
return err;
}
/************************************************************************
* ImportSettings - Import an account's settings
************************************************************************/
OSErr ImportSettings(ImportAccountInfoP account)
{
OSErr err = noErr;
ImportPersDataH persData = nil;
short i;
Boolean added = false;
err = ETLImportSettings(account, &persData);
if ((err == noErr) && persData && *persData)
{
LDRef(persData);
for (i=HandleCount(persData);i--;)
{
if (PersDataIsGood(&((*persData)[i])))
{
AddNewPersonality(&((*persData)[i]));
added = true;
}
}
UL(persData);
// if we added a personality, whack the menus if we need to ...
if (added)
{
if (IMAPExists()) CreateNewPersCaches();
}
else
{
// warn user if no useful settings information was found
ImportError(account->id, kImportSettingsErr, kImportNoSettingsError, err=eofErr, __LINE__);
}
}
ZapHandle(persData);
return (err);
}
/************************************************************************
* PersDataIsGood - can we make a personality out of this data? Don't
* bother creating a personality if these settings are incomplete.
************************************************************************/
Boolean PersDataIsGood(ImportPersDataP persD)
{
return ((persD->accountName[0] && persD->userName[0] && persD->mailServer[0]) // here be enough server information
|| (persD->accountName[0] && persD->realName[0] && persD->returnAddress[0])); // here be enough user information
}
/************************************************************************
* AddNewPersonality - given imported settings, create a new personality
************************************************************************/
void AddNewPersonality(ImportPersDataP persD)
{
PersHandle pers = nil;
Str255 scratch, iStr;
Str31 name;
short i;
PushPers(CurPers);
// use only the first 31 characters of the account name.
persD->accountName[0] = MIN(persD->accountName[0], sizeof(Str31)-1);
// Use the dominant personality?
if (persD->makeDominant!=0)
{
// yes, but only if it's not yet filled in.
CurPers = PersList;
if (!*GetPOPPref(scratch))
pers = CurPers;
}
// create a fresh personality
if (pers == nil)
{
if (pers=PersNew())
{
// pick a unique name for this new personality
PCopy(name, persD->accountName);
if (FindPersByName(name))
{
for (i = 1; i < 99; i++)
{
PCopy(scratch, name);
iStr[0] = 0;
PLCat(iStr, i);
PCat(scratch, iStr);
if (!FindPersByName(scratch))
{
PCopy(name, scratch);
break;
}
}
}
}
else
{
ImportError(kUnspecifiedImportPluginId, kImportSettingsErr, kImportMemError, MemError(), __LINE__);
}
}
// set the settings
if (pers != nil)
{
// set the name of the personality if it's not the dominant
if (pers != PersList)
{
PersSetName(pers, name);
PersSave(pers);
}
CurPers = pers;
// set the imported settings
SetPref(PREF_RETURN, persD->returnAddress);
SetPref(PREF_REALNAME, persD->realName);
SetPref(PREF_STUPID_USER, persD->userName);
SetPref(PREF_STUPID_HOST, persD->mailServer);
SetStupidStuff();
SetPref(PREF_SMTP, persD->smtpServer);
// turn on IMAP if necessary
if (persD->isIMAP) SetPref(PREF_IS_IMAP, YesStr);
else SetPref(PREF_IS_IMAP, NoStr);
// tell the personalities window about the new account
NotifyPersonalitiesWin();
}
PopPers();
}
/************************************************************************
* ImportSignatures - Import an account's signatures
************************************************************************/
OSErr ImportSignatures(ImportAccountInfoP account)
{
OSErr err = noErr;
err = ETLImportSignatures(account);
if (err != noErr)
{
ImportError(account->id, kImportSignaturesErr, kImportSignaturesError, err, __LINE__);
}
return (err);
}
/************************************************************************
* ImportMakeNewSigCalback - given a name and some text, make a signature file
************************************************************************/
short ImportMakeNewSigCalback(Str255 name, Handle sigText)
{
short err = noErr;
FSSpec spec,folderSpec;
long sigSize = GetHandleSize(sigText);
Str255 scratch;
if (sigSize)
{
// find the signature folder
if (noErr != ( err = SubFolderSpec(SIG_FOLDER,&folderSpec))) return err;
// Make a uniquely named signature file
name[0] = MIN(name[0], 31);
SimpleMakeFSSpec(folderSpec.vRefNum,folderSpec.parID,name,&spec);
UniqueSpec(&spec,31);
// special case for signatures with the same name as the Standard sig
if (StringSame(GetRString(scratch, FILE_ALIAS_STANDARD), spec.name))
{
// append a digit onto the end of the signature name
PLCat(spec.name,1);
// and make sure it's unique
UniqueSpec(&spec,31);
}
if ((err=FSpCreate(&spec,CREATOR,'TEXT',smSystemScript))==noErr)
{
// write the converted text out to a file
LDRef(sigText);
err = Blat(&spec, sigText, false);
UL(sigText);
}
else
{
FileSystemError(CREATE_SIG,&spec.name,err);
}
BuildSigList();
}
return (err);
}
/************************************************************************
* ImportAddresses - Import an account's address book
************************************************************************/
OSErr ImportAddresses(ImportAccountInfoP account)
{
OSErr err = noErr;
err = ETLImportAddresses(account);
if (err != noErr)
{
ImportError(account->id, kImportAddressesErr, kImportAddressesError, err, __LINE__);
}
// re-read the nickname files and update the address book if it's open.
if (!AliasWinIsOpen()) GenAliasList();
RegenerateAllAliases(true);
ABTickleHardEnoughToMakeYouPuke();
return (err);
}
/************************************************************************
* ImportMakeAddressBookCallback - make an address book file
************************************************************************/
short ImportMakeAddressBookCallback(Str255 name)
{
short which = -1;
AliasDesc ad;
FSSpec folderSpec;
Str255 scratch;
long dirID;
OSErr err = noErr;
// if we're in free mode, add nicknames to the existing Eudora Nicknames file.
if (IsFreeMode())
{
return (0);
}
Zero(ad);
// The name of the new nick file will be the name passed in
PCopy(ad.spec.name, name);
ad.spec.name[0] = MIN(ad.spec.name[0], MAX_MAILBOX_NAME_LENGTH);
// check to see if a nickname file already exists there
if (!SubFolderSpec(NICK_FOLDER,&folderSpec))
{
SimpleMakeFSSpec(folderSpec.vRefNum,folderSpec.parID,ad.spec.name,&ad.spec);
UniqueSpec(&ad.spec, 31);
}
else
{
SimpleMakeFSSpec(Root.vRef,Root.dirId,GetRString(scratch,NICK_FOLDER),&folderSpec);
FSpDirCreate(&folderSpec,smSystemScript,&dirID);
SubFolderSpec(NICK_FOLDER,&folderSpec);
SimpleMakeFSSpec(folderSpec.vRefNum,folderSpec.parID,ad.spec.name,&ad.spec);
}
// make the new nickname file.
if (NickWinIsOpen())
{
which = NickMakeNewFile(ad.spec.name);
}
else
{
err = MakeResFile(ad.spec.name,ad.spec.vRefNum,ad.spec.parID,CREATOR,'TEXT');
if (err == noErr)
{
if (PtrPlusHand_(&ad,Aliases,sizeof(ad))) err = MemError();
which = HandleCount (Aliases) - 1;
}
}
if ((err != noErr) || !which)
ImportError(kUnspecifiedImportPluginId, kImportAddressesErr, kCreateAddressbookError, err, __LINE__);
return (which);
}
/************************************************************************
* ImportMakeABEntryCallback - make an address book entry
************************************************************************/
OSErr ImportMakeABEntryCallback(short which, Boolean isGroup, UPtr nickName, Handle addresses, Handle notes)
{
OSErr err = noErr;
Str255 name;
Handle mungedAddresses = nil;
// special case call to save address book
if (!nickName && !addresses)
{
SaveIndNickFile(which, true);
return (noErr);
}
BeautifyFrom(nickName);
SanitizeFN(name,nickName,NICK_BAD_CHAR,NICK_REP_CHAR,false);
if (addresses)
{
if ((err=SuckAddresses(&mungedAddresses,addresses,true,false,false,nil))==noErr)
{
// Add this nickname. If we're adding to an existing nickname file, warn about duplicates
err = NewNickLow(mungedAddresses, notes, which, name, true, IsFreeMode()?nrDifferent:nrAdd, false);
}
}
else
{
// Addresses passed in was nil. Just convert the nickname
PCopy(nickName, name);
}
return (err);
}
/************************************************************************
* ZapImportablesHandle - clean up an ImportAccountInfoH
************************************************************************/
void ZapImportablesHandle(ImportAccountInfoH *importables)
{
short i = GetHandleSize(*importables)/sizeof(ImportAccountInfoS);
while (i)
{
ZapHandle((**importables)[i-1].icon);
i--;
}
ZapHandle(*importables);
*importables = nil;
}
/************************************************************************
* ImportError - report an importer error
************************************************************************/
OSErr ImportError(long id, short importOperation, short importError, OSErr err, short line)
{
Str255 message;
Str255 importMessage;
Str63 debugStr;
Str31 rawNumber;
Str255 importerError;
// get the name of the importer that has reported the error
importerError[0] = 0;
if (id >= 0)
{
GetImporterName(id, importerError);
PCat(importerError,"\p:");
}
importMessage[0] = 0;
NumToString(err,rawNumber);
PCat(importerError,rawNumber);
GetRString(message,importOperation+ImportOperationsStrn);
// pick a useful error message
switch (err)
{
case memFullErr:
GetRString(importMessage,ImportErrorsStrn+kImportMemError);
break;
default:
GetRString(importMessage,importError+ImportErrorsStrn);
break;
}
ComposeRString(debugStr,FILE_LINE_FMT,FNAME_STRN+FILE_NUM,line);
MyParamText(message,importerError,importMessage,debugStr);
ReallyDoAnAlert(BIG_OK_ALRT,Caution);
return (err);
}
/************************************************************************
* Import Window data structures and definitions
************************************************************************/
#define NUM_COLUMNS 3
#define THUMB_COLUMN 0
#define ACCOUNT_COLUMN 1
#define PROGRAM_COLUMN 2
#define MINI_BANNER_WIDTH 50
#define ACCOUNT_NAME_WIDTH 225
// Import window controls
enum
{
kctlColumns1=0,
kctlColumns2,
kctlColumns3,
kctlImport,
kctlSelect,
kctlOther
};
#define NUM_CONTROLS 3
typedef struct
{
ViewList list;
MyWindowPtr win;
ControlHandle ctlImport, ctlSelect, ctlOther;
Boolean inited;
short columnLefts[NUM_COLUMNS];
ImportAccountInfoH Importables;
long pluginId;
} WinData;
static WinData gWin;
/************************************************************************
* Import Window 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 DoGrow(MyWindowPtr win,Point *newSize);
static Boolean ImportDrawRowCallBack(ViewListPtr pView,short item,Rect *pRect,CellRec *pCellData,Boolean select,Boolean eraseName);
static Boolean ImportFillBlankCallback(ViewListPtr pView);
static void ImportSelectedAccounts(void);
static void ManualImport(void);
static void GetCellRectsForImportWin(ViewListPtr pView,CellRec *pCellData,Rect *pRect,Rect *pIcon,Rect *pName,Rect *pDate,Point *pNamePt,Point *pDatePt);
static short ColumnRight(short column, short max);
static Boolean ImportGetCellRectsCallBack(ViewListPtr pView, CellRec *cellData, Rect *cellRect, Rect *iconRect, Rect *nameRect);
static Boolean ImportInterestingClickCallBack(ViewListPtr pView, CellRec *cellData, Rect *cellRect, Point pt);
static void SetImportWinBackgroundColor(void);
static Boolean ImportFind(MyWindowPtr win,PStr what);
static void PopuplateImportList(void);
static OSErr BuildListOfImportables(ImportAccountInfoH *importables);
static void SortImportablesHandle(ImportAccountInfoH toSort);
static int ImportAppCompare(ImportAccountInfoP i1, ImportAccountInfoP i2);
static int ImportAccountCompare(ImportAccountInfoP i1, ImportAccountInfoP i2);
static void SwapImportable(ImportAccountInfoP i1, ImportAccountInfoP i2);
/************************************************************************
* OpenImportWindow - open the import window
************************************************************************/
static void OpenImportWindow(long pluginId, Boolean reopen)
{
short err=0;
Rect r;
DrawDetailsStruct details;
WindowPtr gWinWinPtr;
ImportAccountInfoH importables;
if (!gWin.inited || reopen)
{
// which plugin will be used for importing?
gWin.pluginId = pluginId;
// see if we can find anything to import
importables = nil;
err = BuildListOfImportables(&importables);
if ((err != noErr) || (importables==nil))
{
// let the user select something by hand to import if we're using a specific importer plugin ...
if (gWin.pluginId != kUnspecifiedImportPluginId)
{
if (ComposeStdAlert(Note,IMPORT_MESSAGE_BY_HAND)==1)
{
// manual import ...
ManualImport();
}
}
else
{
// Otherwise, the import failed.
if (ComposeStdAlert(Note,IMPORT_MESSAGE_TRY_AGAIN)==1)
{
DoMailImport();
}
}
// we're done
return;
}
// if we're reopening, destroy the old list and importables
if (reopen)
{
if (gWin.inited)
{
LVDispose(&gWin.list);
ZapImportablesHandle(&(gWin.Importables));
}
}
gWin.Importables = importables;
if (!gWin.inited)
{
/*
* the window
*/
if (!(gWin.win=GetNewMyWindow(IMPORTER_WIND,nil,nil,BehindModal,false,false,IMPORTER_WIN)))
{err=MemError(); goto fail;}
gWinWinPtr = GetMyWindowWindowPtr (gWin.win);
SetWinMinSize(gWin.win,-1,-1);
SetPort_(GetMyWindowCGrafPtr(gWin.win));
ConfigFontSetup(gWin.win);
MySetThemeWindowBackground(gWin.win,kThemeListViewBackgroundBrush,False);
/*
* controls
*/
if (!(gWin.ctlImport = NewIconButton(IMPORT_IMPORT_CNTL,gWinWinPtr)) ||
!(gWin.ctlSelect = NewIconButton(IMPORT_SELECT_CNTL,gWinWinPtr)) ||
!(gWin.ctlOther = NewIconButton(IMPORT_OTHER_CNTL,gWinWinPtr)))
goto fail;
/*
* columns
*/
gWin.columnLefts[THUMB_COLUMN] = 0;
gWin.columnLefts[ACCOUNT_COLUMN] = MINI_BANNER_WIDTH+2;
gWin.columnLefts[PROGRAM_COLUMN] = gWin.columnLefts[THUMB_COLUMN] + ACCOUNT_NAME_WIDTH;
/*
* callbacks
*/
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 = nil;
gWin.win->find = ImportFind;
gWin.win->showsSponsorAd = true;
}
/*
* the list
*/
details.arrowLeft = 2;
details.iconTop = 2;
details.iconLeft = details.arrowLeft; // First icon level
details.iconLevelWidth = 0;
details.textBottom = 5;
details.rowHt = 36;
details.nameAddMargin = 5; // Add to name width when drawing
details.maxNameWidth = ACCOUNT_NAME_WIDTH; // Approximate maximum name width
details.keyNavTicks = 60; // Delay accepted between navigation keys
// callbacks for list drawing
details.DrawRowCallback = ImportDrawRowCallBack;
details.FillBlankCallback = ImportFillBlankCallback;
details.GetCellRectsCallBack = ImportGetCellRectsCallBack;
details.InterestingClickCallback = ImportInterestingClickCallBack;
SetRect(&r,0,0,20,20);
if (LVNewWithDetails(&gWin.list,gWin.win,&r,1,ViewListCallBack,flavorTypeText,&details))
{err=MemError(); goto fail;}
/*
* show the window
*/
MyWindowDidResize(gWin.win,&gWin.win->contR);
ShowMyWindow(gWinWinPtr);
gWin.inited = true;
UserSelectWindow(GetMyWindowWindowPtr(gWin.win));
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[NUM_CONTROLS];
Rect r;
short htAdjustment;
// buttons
ctlList[0] = gWin.ctlImport;
ctlList[1] = gWin.ctlSelect;
ctlList[2] = gWin.ctlOther;
PositionBevelButtons(win,NUM_CONTROLS,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)
{
short count = LVCountSelection(&gWin.list);
Boolean fSelect = count!=0;
// enable/disable buttons
SetGreyControl(gWin.ctlImport,!fSelect);
SetGreyControl(gWin.ctlSelect,(gWin.pluginId==kUnspecifiedImportPluginId));
SetGreyControl(gWin.ctlOther,false);
}
/************************************************************************
* 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)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
Rect r;
short htControl = ControlHi(gWin.ctlImport);
short bottomMargin,sponsorMargin;
// Get list position
bottomMargin = INSET*2 + htControl;
if (win->sponsorAdExists)
{
Rect rPort;
GetPortBounds(GetMyWindowCGrafPtr(win),&rPort);
sponsorMargin = rPort.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;
// dispose of importables list
ZapImportablesHandle(&(gWin.Importables));
}
return(True);
}
/************************************************************************
* IsImportWindowOpen - is the import window open?
************************************************************************/
static Boolean IsImportWindowOpen(void)
{
return (gWin.inited);
}
/************************************************************************
* DoUpdate - draw the window
************************************************************************/
static void DoUpdate(MyWindowPtr win)
{
Rect r;
// Tweak the import window colors
SetImportWinBackgroundColor();
// draw the list
r = gWin.list.bounds;
DrawThemeListBoxFrame(&r,kThemeStateActive);
LVDraw(&gWin.list, MyGetPortVisibleRegion(GetMyWindowCGrafPtr(win)), true, false);
}
/************************************************************************
* DoActivate - activate the window
************************************************************************/
static void DoActivate(MyWindowPtr win)
{
#pragma unused(win)
LVActivate(&gWin.list, gWin.win->isActive);
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;
}
/**********************************************************************
* ImportFind - find in the window
**********************************************************************/
static Boolean ImportFind(MyWindowPtr win,PStr what)
{
return FindListView(win,&gWin.list,what);
}
/************************************************************************
* DoClick - click in window
************************************************************************/
static 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)))
{
if (hCtl == gWin.ctlImport)
{
ImportSelectedAccounts();
AuditHit((event->modifiers&shiftKey)!=0, (event->modifiers&controlKey)!=0, (event->modifiers&optionKey)!=0, (event->modifiers&cmdKey)!=0, false, GetWindowKind(winWP), AUDITCONTROLID(GetWindowKind(winWP),kctlImport), event->what);
}
else if (hCtl == gWin.ctlSelect)
{
ManualImport();
AuditHit((event->modifiers&shiftKey)!=0, (event->modifiers&controlKey)!=0, (event->modifiers&optionKey)!=0, (event->modifiers&cmdKey)!=0, false, GetWindowKind(winWP), AUDITCONTROLID(GetWindowKind(winWP),kctlSelect), event->what);
}
else if (hCtl == gWin.ctlOther)
{
DoMailImport();
AuditHit((event->modifiers&shiftKey)!=0, (event->modifiers&controlKey)!=0, (event->modifiers&optionKey)!=0, (event->modifiers&cmdKey)!=0, false, GetWindowKind(winWP), AUDITCONTROLID(GetWindowKind(winWP),kctlOther), event->what);
}
}
}
}
SetControls();
}
/************************************************************************
* 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,IMPORT_HELP_STRN+1,0,nil);
else
ShowControlHelp(mouse,IMPORT_HELP_STRN+2,gWin.ctlImport,gWin.ctlSelect,gWin.ctlOther,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:
ImportSelectedAccounts();
return(True);
break;
}
break;
case EDIT_MENU:
if (item==EDIT_SELECT_ITEM)
{
if (LVSelectAll(&gWin.list))
{
SetControls();
return(true);
}
}
break;
}
return(False);
}
/**********************************************************************
* DoDragHandler - handle drags
**********************************************************************/
static OSErr DoDragHandler(MyWindowPtr win,DragTrackingMessage which,DragReference drag)
{
#pragma unused(win)
#pragma unused(which)
#pragma unused(drag)
return(dragNotAcceptedErr); // Nothing here we want
}
/************************************************************************
* ImportFillBlankCallback - callback function for List View. Fill unused
* parts of the list.
************************************************************************/
static Boolean ImportFillBlankCallback(ViewListPtr pView)
{
ListHandle hList=pView->hList;
Rect rErase;
GrafPtr savePort;
short column;
Rect columnRect;
if ((*hList)->visible.bottom > (*hList)->dataBounds.bottom)
{
SAVE_STUFF;
SET_COLORS;
GetPort(&savePort);
SetPort(GetMyWindowCGrafPtr(pView->wPtr));
Cell1Rect(hList,(*hList)->dataBounds.bottom+1,&rErase);
rErase.bottom = pView->bounds.bottom;
if (UseListColors)
{
for (column = 0; column < NUM_COLUMNS; column++)
{
// what is the rect describing this column?
SetRect(&columnRect,rErase.left+gWin.columnLefts[column],rErase.top,rErase.left+ColumnRight(column,rErase.right),rErase.bottom);
// color this column
SetThemeBackground(column==PROGRAM_COLUMN ? kThemeBrushListViewSortColumnBackground:kThemeBrushListViewBackground,RectDepth(&columnRect),true);
EraseRect(&columnRect);
}
}
SetPort(savePort);
REST_STUFF;
}
return true; /* mtc sez - this value is never checked 11-18-03 */
}
/************************************************************************
* ColumnRight - return the right side of a column
************************************************************************/
static short ColumnRight(short column, short max)
{
short right = 0;
if ((column>=0) && (column<NUM_COLUMNS))
{
if (column < NUM_COLUMNS - 1)
right = gWin.columnLefts[column+1];
else
right = max;
}
return (right);
}
/************************************************************************
* ImportDrawRowCallBack - callback function for List View. Draw a row.
************************************************************************/
static Boolean ImportDrawRowCallBack(ViewListPtr pView,short item,Rect *pRect,CellRec *pCellData,Boolean select,Boolean eraseName)
{
Boolean result = true;
Rect rIcon, rName, rApplication;
Point ptName, ptApplication;
Boolean hasColor = IsColorWin(GetMyWindowWindowPtr(pView->wPtr));
Str255 scratch;
short column;
Rect columnRect;
Handle theIcon;
if (item && item <= (*pView->hList)->dataBounds.bottom)
{
SAVE_STUFF;
//
// Figure out where things are in this row
//
GetCellRectsForImportWin(pView,pCellData,pRect,&rIcon,&rName,&rApplication,&ptName,&ptApplication);
//
// Draw the list background color and seperator lines for this row
//
if (UseListColors)
{
for (column = 0; column < NUM_COLUMNS; column++)
{
// what is the rect describing this column?
SetRect(&columnRect,pRect->left+gWin.columnLefts[column],pRect->top,pRect->left+ColumnRight(column,pRect->right),pRect->top + (*pView->hList)->cellSize.v - 1);
// color this column
if (column==PROGRAM_COLUMN)
SetThemeBackground(kThemeBrushListViewSortColumnBackground,RectDepth(&columnRect),true);
else
SetThemeBackground(kThemeBrushListViewBackground,RectDepth(&columnRect),true);
EraseRect(&columnRect);
}
SET_COLORS;
}
//
// Draw the contents of this item
//
SET_COLORS;
// Plot the icon
theIcon = GetImporterAppIcon(pCellData->iconID);
if (theIcon) PlotIconSuite(&rIcon, atNone + atHorizontalCenter, select ? ttSelected : ttNone, theIcon);
else PlotIconID(&rIcon,atNone + atHorizontalCenter,select ? ttSelected : ttNone,IMPORT_IMPORT_CNTL);
// Draw the account name
MoveTo(ptName.h,ptName.v);
if (eraseName)
EraseRect(&rName);
if (pCellData->misc.style)
TextFace(pCellData->misc.style);
TextFont(pView->font);
TextSize(pView->fontSize);
DrawString(pCellData->name);
if (pCellData->misc.style)
TextFace(0);
if (select)
InvertRect(&rName);
// Draw the application name
PCopy(scratch, (*(gWin.Importables))[item-1].appName);
MoveTo(ptApplication.h,ptApplication.v);
if (eraseName)
EraseRect(&rApplication);
if (pCellData->misc.style)
TextFace(pCellData->misc.style);
TextFont(pView->font);
TextSize(pView->fontSize);
DrawString(scratch);
if (pCellData->misc.style)
TextFace(0);
REST_STUFF;
}
return (result);
}
/**********************************************************************
* GetCellRects - get triangle, icon, and name rects
**********************************************************************/
static void GetCellRectsForImportWin(ViewListPtr pView,CellRec *pCellData,Rect *pRect,Rect *pIcon,Rect *pName,Rect *pDate,Point *pNamePt,Point *pDatePt)
{
short offset;
Point pt;
FontInfo fInfo;
short column;
SAVE_STUFF;
for (column = 0; column < NUM_COLUMNS; column++)
{
switch (column)
{
case THUMB_COLUMN:
if (column < NUM_COLUMNS - 1)
{
// center of column, minus half of an icon
offset = (gWin.columnLefts[column+1] - gWin.columnLefts[column])/2 - 16;
}
else
{
// half an icon away from the leftmost part of the column
offset = gWin.columnLefts[column] + 48;
}
SetRect(pIcon,pRect->left+offset,pRect->top+(pView->details.iconTop),pRect->left+offset+32,pRect->top+(pView->details.iconTop)+32);
break;
case ACCOUNT_COLUMN:
case PROGRAM_COLUMN:
offset = gWin.columnLefts[column] + (pView->details.nameAddMargin);
TextFont(pView->font);
TextSize(pView->fontSize);
pt.h = pRect->left + offset;
pt.v = pRect->top+((*pView->hList)->cellSize.v/2)+(pView->fontSize)/2; // center the text vertically
GetFontInfo(&fInfo);
if (column==ACCOUNT_COLUMN)
{
*pNamePt = pt;
SetRect(pName,pt.h,pt.v-fInfo.ascent-fInfo.leading,pt.h + StringWidth(pCellData->name),pt.v+fInfo.descent);
}
else if (column==PROGRAM_COLUMN)
{
*pDatePt = pt;
SetRect(pDate,pt.h,pt.v-fInfo.ascent-fInfo.leading,pt.h + StringWidth(pCellData->name),pt.v+fInfo.descent);
}
break;
default:
break;
}
}
REST_STUFF;
}
/************************************************************************
* ViewListCallBack - callback function for List View
************************************************************************/
static long ViewListCallBack(ViewListPtr pView, VLCallbackMessage message, long data)
{
VLNodeInfo *pInfo;
OSErr err = noErr;
switch (message)
{
case kLVAddNodeItems:
PopuplateImportList();
break;
case kLVOpenItem:
ImportSelectedAccounts();
break;
case kLVDeleteItem:
break;
case kLVRenameItem:
break;
case kLVQueryItem:
pInfo = ( VLNodeInfo *)data;
switch (pInfo->query)
{
case kQuerySelect:
case kQueryDCOpens:
return true;
case kQueryDrag:
case kQueryDrop:
case kQueryRename:
return false;
}
break;
case kLVSendDragData:
break;
}
return err;
}
/************************************************************************
* PopuplateImportList - search for importable things
************************************************************************/
static void PopuplateImportList(void)
{
OSErr err = noErr;
ViewListPtr pView = &gWin.list;
VLNodeInfo info;
short count, i;
// Add items from list of importable accounts we built earlier ...
if (gWin.Importables)
{
count = GetHandleSize(gWin.Importables)/sizeof(ImportAccountInfoS);
for (i=0;i<count;i++)
{
Zero(info);
PStrCopy(info.name,(*gWin.Importables)[i].accountName,sizeof(info.name));
info.iconID = (*gWin.Importables)[i].id;
LVAdd(pView, &info);
}
}
}
/************************************************************************
* BuildListOfImportables - build a list of all importable accounts on
* this machine.
************************************************************************/
static OSErr BuildListOfImportables(ImportAccountInfoH *importables)
{
OSErr err = noErr;
// initialize it
*importables = NuHandle(0L);
err = MemError();
if ((err==noErr) && *importables)
{
ETLQueryImporters(importables, gWin.pluginId, true);
// did we find something?
if (GetHandleSize(*importables) > 0)
{
// Sort the resulting list of importables
if (importables && *importables && **importables)
SortImportablesHandle(*importables);
}
else
{
ZapHandle(*importables);
}
}
return (err);
}
/************************************************************************
* ImportSelectedAccounts - import all selected accounts
************************************************************************/
static void ImportSelectedAccounts(void)
{
short i;
VLNodeInfo info;
for (i=1;i<=LVCountSelection(&gWin.list);i++)
{
GetListData(&info,i);
LDRef(gWin.Importables);
ImportAccount(&(*(gWin.Importables))[info.rowNum-1]);
UL(gWin.Importables);
}
}
/************************************************************************
* ManualImport - prompt the user to select a folder to import
************************************************************************/
static void ManualImport(void)
{
OSErr err = -1;
Str255 volName;
short vRef;
long dirId;
ImportAccountInfoS importThis;
// set up an account info structure to do the importing ...
Zero(importThis);
importThis.size = sizeof(ImportAccountInfoS);
importThis.id = gWin.pluginId;
while (err && (err != userCanceledErr))
{
if (GetFolder(volName,&vRef,&dirId,false,false,false,false))
{
SimpleMakeFSSpec(vRef, dirId, "\p", &importThis.importSpec);
GetDirName(volName,vRef,dirId,importThis.importSpec.name);
PCopy(importThis.accountName,importThis.importSpec.name);
err = ImportAccount(&importThis);
}
else err = userCanceledErr;
}
}
/************************************************************************
* ImportInterestingClickCallBack - return true if this point is interesting
************************************************************************/
static Boolean ImportInterestingClickCallBack(ViewListPtr pView, CellRec *cellData, Rect *cellRect, Point pt)
{
Boolean result = false;
Rect rIcon, rName, rApplication;
Point ptName, ptApplication;
GetCellRectsForImportWin(pView,cellData,cellRect,&rIcon,&rName,&rApplication,&ptName,&ptApplication);
if (PtInRect(pt,&rIcon) || PtInRect(pt,&rName) || PtInRect(pt,&rApplication)) result = true;
return (result);
}
/**********************************************************************
* GetCellData - Get data for cell,item is 0-based
**********************************************************************/
static short GetCellData(ViewListPtr pView,short item,CellRec *pCellData)
{
short dataLen;
Cell c;
dataLen = sizeof(CellRec);
c.h = 0; c.v = item;
LGetCell((Ptr)pCellData, &dataLen, c, pView->hList);
return dataLen;
}
/************************************************************************
* ImportGetCellRectsCallBack - return true if this we should drag
************************************************************************/
static Boolean ImportGetCellRectsCallBack(ViewListPtr pView, CellRec *cellData, Rect *cellRect, Rect *iconRect, Rect *nameRect)
{
Rect rApplication;
Point ptName, ptApplication;
GetCellRectsForImportWin(pView,cellData,cellRect,iconRect,nameRect,&rApplication,&ptName,&ptApplication);
return (true);
}
/************************************************************************
* SetImportWinBackgroundColor - set the background color of this win
************************************************************************/
static void SetImportWinBackgroundColor(void)
{
if (UseListColors)
{
// Using finder list color scheme. Punt on background color.
gWin.win->backColor.red = gWin.win->backColor.green = gWin.win->backColor.blue = 0xffff;
}
else
{
// Using BACK_COLOR.
GetRColor(&gWin.win->backColor,BACK_COLOR);
}
}
/************************************************************************
* SortImportablesHandle - sort a list of importables
************************************************************************/
static void SortImportablesHandle(ImportAccountInfoH toSort)
{
short count = 0;
count = GetHandleSize(toSort)/sizeof(ImportAccountInfoS);
QuickSort((void*)LDRef(toSort),sizeof(ImportAccountInfoS),0,count-1,ImportAccountCompare,(void*)SwapImportable);
QuickSort((void*)LDRef(toSort),sizeof(ImportAccountInfoS),0,count-1,ImportAppCompare,(void*)SwapImportable);
UL(toSort);
}
/**********************************************************************
* ImportAppCompare - compare two cells based on their application
**********************************************************************/
static int ImportAppCompare(ImportAccountInfoP i1, ImportAccountInfoP i2)
{
return (StringComp(i2->appName,i1->appName));
}
/**********************************************************************
* ImportAccountCompare - compare two cells based on thir name
**********************************************************************/
static int ImportAccountCompare(ImportAccountInfoP i1, ImportAccountInfoP i2)
{
return (StringComp(i2->importSpec.name,i1->importSpec.name));
}
/**********************************************************************
* SwapImportable - swap two importable entries.
**********************************************************************/
static void SwapImportable(ImportAccountInfoP i1, ImportAccountInfoP i2)
{
ImportAccountInfoS tempI;
tempI = *i1;
*i1 = *i2;
*i2 = tempI;
}