📄 addresstransfer.c
字号:
/******************************************************************************
*
* Copyright (c) 1995-2003 PalmSource, Inc. All rights reserved.
*
* File: AddressTransfer.c
*
* Release: Palm OS 5 SDK (68K) R3.
*
* Description:
* Address Book routines to transfer records.
*
*****************************************************************************/
#include "Address.h"
#include "AddressTransfer.h"
#include "AddressRsc.h"
#include "AddrDefines.h"
#include "AddrTools.h"
#include <TraceMgr.h>
#include <PdiLib.h>
#include <UDAMgr.h>
#include <ErrorMgr.h>
#include <UIResources.h>
#include <StringMgr.h>
#include <Category.h>
#include <PalmLocale.h>
/***********************************************************************
*
* Defines
*
***********************************************************************/
#define identifierLengthMax 40
#define addrFilenameExtension "vcf"
#define addrFilenameExtensionLength 3
#define addrMIMEType "text/x-vCard"
// Aba: internal version of vCalendar. Must be updated
// the export side of the vCalendar code evoluate
#define kVObjectVersion "5.3"
/***********************************************************************
*
* Internal Functions
*
***********************************************************************/
static Err PrvTransferPdiLibLoad(UInt16* refNum, Boolean *loadedP);
static void PrvTransferPdiLibUnload(UInt16 refNum, Boolean loaded);
static Err PrvTransferSendRecordTryCatch (DmOpenRef dbP, Int16 recordNum, AddrDBRecordPtr recordP, UDAWriterType* media);
static void PrvTransferCleanFileName(Char* ioFileName);
static Err PrvTransferSendCategoryTryCatch (DmOpenRef dbP, UInt16 categoryNum, UDAWriterType* media, UInt16 index);
static void PrvTransferSetGoToParams (DmOpenRef dbP, ExgSocketPtr exgSocketP, UInt32 uniqueID);
static MemHandle PrvTransferGetFullName (AddrDBRecordPtr r, Int16 useCompany);
static Boolean PrvTransferAlternateFieldExists(AddrDBRecordPtr recordP);
/***********************************************************************
*
* FUNCTION: TransferRegisterData
*
* DESCRIPTION: Register with the exchange manager to receive data
* with a certain name extension.
*
* PARAMETERS: nothing
*
* RETURNED: nothing
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* rsf 12/2/97 Created
*
***********************************************************************/
void TransferRegisterData (void)
{
MemHandle resH = DmGetResource(strRsc, ExgDescriptionStr);
void *desc = MemHandleLock(resH);
ExgRegisterDatatype(sysFileCAddress, exgRegExtensionID, addrFilenameExtension, desc, 0);
ExgRegisterDatatype(sysFileCAddress, exgRegTypeID, addrMIMEType, desc, 0);
MemHandleUnlock(resH);
DmReleaseResource(resH);
}
/***********************************************************************
*
* FUNCTION: TransferSendRecord
*
* DESCRIPTION: Send a record.
*
* PARAMETERS: dbP - pointer to the database to add the record to
* recordNum - the record to send
* prefix - the scheme with ":" suffix and optional "?" prefix
* noDataAlertID - alert to put up if there is nothing to send
*
* RETURNED: true if the record is found and sent
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* roger 5/9/97 Initial Revision
* dje 4/24/00 Don't specify target creator ID
* ABa 6/20/00 Integrate Pdi library
* vsm 12/5/02 Use PrvTransferGetFullName to lay out the name fields
* in the appropriate order.
*
***********************************************************************/
void TransferSendRecord (DmOpenRef dbP, Int16 recordNum, const Char * const prefix, UInt16 noDataAlertID)
{
AddrDBRecordType record;
MemHandle recordH;
MemHandle descriptionH;
UInt16 descriptionSize = 0;
Int16 descriptionWidth;
Boolean descriptionFit;
UInt16 newDescriptionSize;
MemHandle nameH;
MemHandle resourceH;
Char *resourceP;
Err error;
ExgSocketType exgSocket;
UDAWriterType* media;
UInt8 schemeLength;
TraceInit();
TraceOutput(TL(appErrorClass, "Pdi Version"));
// important to init structure to zeros...
MemSet(&exgSocket, sizeof(exgSocket), 0);
// Form a description of what's being sent. This will be displayed
// by the system send dialog on the sending and receiving devices.
error = AddrDBGetRecord (dbP, recordNum, &record, &recordH);
ErrNonFatalDisplayIf(error, "Can't get record");
if (AddrDBRecordContainsData(&record))
{
descriptionH = PrvTransferGetFullName (&record, SortByCompany);
if (descriptionH)
{
exgSocket.description = MemHandleLock(descriptionH);
descriptionSize = StrLen(exgSocket.description);
}
// Truncate the description if too long
if (descriptionSize > 0)
{
// Make sure the description isn't too long.
newDescriptionSize = descriptionSize;
WinGetDisplayExtent(&descriptionWidth, NULL);
FntCharsInWidth (exgSocket.description, &descriptionWidth, (Int16 *)&newDescriptionSize, &descriptionFit);
if (newDescriptionSize > 0)
{
if (newDescriptionSize != descriptionSize)
{
exgSocket.description[newDescriptionSize] = nullChr;
MemHandleUnlock(descriptionH);
MemHandleResize(descriptionH, newDescriptionSize + sizeOf7BitChar('\0'));
exgSocket.description = MemHandleLock(descriptionH);
}
}
else
{
MemHandleFree(descriptionH);
descriptionH = NULL;
}
descriptionSize = newDescriptionSize;
}
// Make a filename
schemeLength = StrLen(prefix);
if (descriptionSize > 0)
{
// Now make a filename from the description
nameH = MemHandleNew(schemeLength + imcFilenameLength);
exgSocket.name = MemHandleLock(nameH);
StrCopy(exgSocket.name, prefix);
StrNCat(exgSocket.name, exgSocket.description,
schemeLength + imcFilenameLength - addrFilenameExtensionLength - sizeOf7BitChar('.'));
StrCat(exgSocket.name, ".");
StrCat(exgSocket.name, addrFilenameExtension);
}
else
{
// A description is needed. Either there never was one or the first line wasn't usable.
if (descriptionH)
MemHandleFree(descriptionH);
descriptionH = DmGetResource(strRsc, BeamDescriptionStr);
exgSocket.description = MemHandleLock(descriptionH);
resourceH = DmGetResource(strRsc, BeamFilenameStr);
resourceP = MemHandleLock(resourceH);
nameH = MemHandleNew(schemeLength + StrLen(resourceP) + 1);
exgSocket.name = MemHandleLock(nameH);
StrCopy(exgSocket.name, prefix);
StrCat(exgSocket.name, resourceP);
MemHandleUnlock(resourceH);
DmReleaseResource(resourceH);
}
//ABa: remove superfluous '.' characters
PrvTransferCleanFileName(exgSocket.name);
exgSocket.length = MemHandleSize(recordH) + 100; // rough guess
//exgSocket.target = sysFileCAddress; // commented out 4/24/00 dje
exgSocket.type = (Char *)addrMIMEType;
error = ExgPut(&exgSocket); // put data to destination
TraceOutput(TL(appErrorClass, "TransferSendRecord: description = %s, name = %s", exgSocket.description, exgSocket.name));
// ABa: Changes to use new streaming mechanism
media = UDAExchangeWriterNew(&exgSocket, 512);
if (!error)
{
if (media)
error = PrvTransferSendRecordTryCatch(dbP, recordNum, &record, media);
else
error = exgMemError;
ExgDisconnect(&exgSocket, error);
}
if (media)
UDADelete(media);
// Clean up
if (descriptionH)
{
MemHandleUnlock (descriptionH);
if (MemHandleDataStorage (descriptionH))
DmReleaseResource(descriptionH);
else
MemHandleFree(descriptionH);
}
if (nameH)
{
MemHandleUnlock (nameH);
if (MemHandleDataStorage (nameH))
DmReleaseResource(nameH);
else
MemHandleFree(nameH);
}
}
else
FrmAlert(noDataAlertID);
MemHandleUnlock(recordH);
// No need to release the record because AddrDBGetRecord didn't mark it busy.
//DmReleaseRecord(dbP, recordNum, false);
TraceClose();
return;
}
/***********************************************************************
*
* FUNCTION: TransferSendCategory
*
* DESCRIPTION: Send all visible records in a category.
*
* PARAMETERS: dbP - pointer to the database to add the record to
* categoryNum - the category of records to send
* prefix - the scheme with ":" suffix and optional "?" prefix
* noDataAlertID - alert to put up if there is nothing to send
*
* RETURNED: true if any records are found and sent
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* roger 5/9/97 Initial Revision
* dje 4/24/00 Don't specify target creator ID
*
***********************************************************************/
void TransferSendCategory (DmOpenRef dbP, UInt16 categoryNum, const Char * const prefix, UInt16 noDataAlertID)
{
Err error;
Char description[dmCategoryLength];
UInt16 index;
Boolean foundAtLeastOneRecord;
ExgSocketType exgSocket;
UInt16 mode;
LocalID dbID;
UInt16 cardNo;
Boolean databaseReopened;
UDAWriterType* media;
TraceInit();
// If the database was opened to show secret records, reopen it to not see
// secret records. The idea is that secret records are not sent when a
// category is sent. They must be explicitly sent one by one.
DmOpenDatabaseInfo(dbP, &dbID, NULL, &mode, &cardNo, NULL);
if (mode & dmModeShowSecret)
{
dbP = DmOpenDatabase(cardNo, dbID, dmModeReadOnly);
databaseReopened = true;
}
else
databaseReopened = false;
// important to init structure to zeros...
MemSet(&exgSocket, sizeof(exgSocket), 0);
// Make sure there is at least one record in the category.
index = 0;
foundAtLeastOneRecord = false;
while (true)
{
if (DmSeekRecordInCategory(dbP, &index, 0, dmSeekForward, categoryNum) != 0)
break;
foundAtLeastOneRecord = DmQueryRecord(dbP, index) != 0;
if (foundAtLeastOneRecord)
break;
index++;
}
// We should send the category because there's at least one record to send.
if (foundAtLeastOneRecord)
{
// Form a description of what's being sent. This will be displayed
// by the system send dialog on the sending and receiving devices.
CategoryGetName (dbP, categoryNum, description);
exgSocket.description = description;
// Now form a file name
exgSocket.name = MemPtrNew(StrLen(prefix) + StrLen(description) + sizeOf7BitChar('.') + StrLen(addrFilenameExtension) + sizeOf7BitChar('\0'));
if (exgSocket.name)
{
StrCopy(exgSocket.name, prefix);
StrCat(exgSocket.name, description);
StrCat(exgSocket.name, ".");
StrCat(exgSocket.name, addrFilenameExtension);
}
// ABa: remove superfluous '.' chars
PrvTransferCleanFileName(exgSocket.name);
exgSocket.length = 0; // rough guess
//exgSocket.target = sysFileCAddress; // commented out 4/24/00 dje
exgSocket.type = (Char *)addrMIMEType;
error = ExgPut(&exgSocket); // put data to destination
media = UDAExchangeWriterNew(&exgSocket, 512);
if (!error)
{
if (media)
error = PrvTransferSendCategoryTryCatch (dbP, categoryNum, media, index);
else
error = exgMemError;
ExgDisconnect(&exgSocket, error);
}
// Release file name
if (exgSocket.name)
MemPtrFree(exgSocket.name);
if (media)
UDADelete(media);
}
else
FrmAlert(noDataAlertID);
if (databaseReopened)
DmCloseDatabase(dbP);
TraceClose();
return;
}
/***********************************************************************
*
* FUNCTION: ReceiveData
*
* DESCRIPTION: Receives data into the output field using the Exg API
*
* PARAMETERS: exgSocketP, socket from the app code
* sysAppLaunchCmdExgReceiveData
*
* RETURNED: error code or zero for no error.
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* ABa 6/20/00 Integrate Pdi library
*
***********************************************************************/
Err TransferReceiveData(DmOpenRef dbP, ExgSocketPtr exgSocketP)
{
volatile Err err;
UInt16 pdiRefNum = sysInvalidRefNum;
PdiReaderType* reader = NULL;
UDAReaderType* stream = NULL;
Boolean loaded;
// accept will open a progress dialog and wait for your receive commands
if ((err = ExgAccept(exgSocketP)) != 0)
return err;
TraceInit();
if ((err = PrvTransferPdiLibLoad(&pdiRefNum, &loaded)))
{
pdiRefNum = sysInvalidRefNum;
goto errorDisconnect;
}
if ((stream = UDAExchangeReaderNew(exgSocketP)) == NULL)
{
err = exgMemError;
goto errorDisconnect;
}
if ((reader = PdiReaderNew(pdiRefNum, stream, kPdiOpenParser)) == NULL)
{
err = exgMemError;
goto errorDisconnect;
}
reader->appData = exgSocketP;
ErrTry
{
// Keep importing records until it can't
while(TransferImportVCard(dbP, pdiRefNum, reader, false, false)){};
}
ErrCatch(inErr)
{
err = inErr;
} ErrEndCatch
// Aba: A record has been added in the Database iff the GoTo
// uniqueID parameter != 0.
// In the case no record is added, return an error
if (err == errNone && exgSocketP->goToParams.uniqueID == 0)
err = exgErrBadData;
errorDisconnect:
if (reader)
PdiReaderDelete(pdiRefNum, &reader);
if (stream)
UDADelete(stream);
if (pdiRefNum != sysInvalidRefNum)
PrvTransferPdiLibUnload(pdiRefNum, loaded);
ExgDisconnect(exgSocketP, err); // closes transfer dialog
err = errNone; // error was reported, so don't return it
TraceClose();
return err;
}
/************************************************************
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -