📄 todotransfer.c
字号:
if (!error)
{
if (media)
error = ToDoSendRecordTryCatch(dbP, recordNum, recordP, media);
else
error = exgMemError;
// Release the record before the database is sorted in loopback mode.
if (recordH)
{
MemHandleUnlock(recordH);
DmReleaseRecord(dbP, recordNum, false);
recordH = NULL;
}
ExgDisconnect(&exgSocket, error);
}
if (media)
UDADelete(media);
// Clean up
if (descriptionH)
MemHandleFree(descriptionH);
if (nameH)
MemHandleFree(nameH);
}
else
FrmAlert(noDataAlertID);
if (recordH)
{
MemHandleUnlock(recordH);
DmReleaseRecord(dbP, recordNum, false);
}
return;
}
/***********************************************************************
*
* FUNCTION: ToDoSendCategoryTryCatch
*
* 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
* exgSocketP - the exchange socket used to send
* index - the record number of the first record in the category to send
*
* RETURNED: 0 if there's no error
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* roger 12/11/97 Initial Revision
*
***********************************************************************/
static Err ToDoSendCategoryTryCatch (DmOpenRef dbP, UInt16 categoryNum,
UDAWriterType* media, UInt16 recordNum)
{
volatile Err error = 0;
volatile MemHandle outRecordH = 0;
ToDoDBRecordPtr outRecordP;
UInt16 pdiRefNum;
PdiWriterType* writer;
Boolean loaded;
if ((error = PrvPdiLibLoad(&pdiRefNum, &loaded)))
return error;
writer = PdiWriterNew(pdiRefNum, media, kPdiPalmCompatibility);
if (writer)
{
// An error can happen anywhere during the send process. It's easier just to
// catch the error. If an error happens, we must pass it into ExgDisconnect.
// It will then cancel the send and display appropriate ui.
ErrTry
{
PdiWriteBeginObject(pdiRefNum, writer, kPdiPRN_BEGIN_VCALENDAR);
PdiWriteProperty(pdiRefNum, writer, kPdiPRN_VERSION);
PdiWritePropertyValue(pdiRefNum, writer, (Char*)"1.0", kPdiWriteData);
// Loop through all records in the category.
while (DmSeekRecordInCategory(dbP, &recordNum, 0, dmSeekForward, categoryNum) == 0)
{
// Emit the record. If the record is private do not emit it.
outRecordH = (MemHandle) DmQueryRecord(dbP, recordNum);
if (outRecordH != 0)
{
outRecordP = (ToDoDBRecordPtr) MemHandleLock(outRecordH);
ToDoExportVCal(dbP, recordNum, outRecordP, pdiRefNum, writer, true);
MemHandleUnlock(outRecordH);
}
recordNum++;
}
PdiWriteEndObject(pdiRefNum, writer, kPdiPRN_END_VCALENDAR);
error = UDAWriterFlush(media);
}
ErrCatch(inErr)
{
error = inErr;
if (outRecordH)
MemHandleUnlock(outRecordH);
} ErrEndCatch
PdiWriterDelete(pdiRefNum, &writer);
}
else
{
error = exgMemError;
}
PrvPdiLibUnload(pdiRefNum, loaded);
return error;
}
/***********************************************************************
*
* FUNCTION: ToDoSendCategory
*
* DESCRIPTION: Send all visible records in a category.
*
* PARAMETERS: dbP - pointer to the database
* 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
*
***********************************************************************/
extern void ToDoSendCategory (DmOpenRef dbP, UInt16 categoryNum, const Char * const prefix, UInt16 noDataAlertID)
{
Err error;
Char description[dmCategoryLength];
UInt16 recordNum;
Boolean foundAtLeastOneRecord;
ExgSocketType exgSocket;
UInt16 mode;
LocalID dbID;
UInt16 cardNo;
Boolean databaseReopened;
UDAWriterType* media;
// 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.
recordNum = 0;
foundAtLeastOneRecord = false;
while (true)
{
if (DmSeekRecordInCategory(dbP, &recordNum, 0, dmSeekForward, categoryNum) != 0)
break;
foundAtLeastOneRecord = DmQueryRecord(dbP, recordNum) != 0;
if (foundAtLeastOneRecord)
break;
recordNum++;
}
// DOLATER ??? -蔠eird edge case: if the only record in the category is an empty record,
// there will still be nothing to beam. Result seems to be getting an empty
// record at the other end, which immediately goes away. Good enough!
// 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) + StrLen(todoSuffix) + sizeOf7BitChar('\0'));
if (exgSocket.name)
{
StrCopy(exgSocket.name, prefix);
StrCat(exgSocket.name, description);
StrCat(exgSocket.name, todoSuffix);
}
//ABa: remove superfluous '.' characters
PrvTransferCleanFileName(exgSocket.name);
exgSocket.length = 0; // rough guess
// Note, a hack in exgmgr will remap this to datebook
// NOTE: ABa To test that the DateBook sublaunches the ToDo app
// when parsing VTODO, just comment out the next line
// And do the same in ToDoSendRecord
exgSocket.target = sysFileCToDo; // include target since todo and date book share an extension
exgSocket.type = (Char *)todoMIMEType;
error = ExgPut(&exgSocket); // put data to destination
media = UDAExchangeWriterNew(&exgSocket, 512);
if (!error)
{
if (media)
error = ToDoSendCategoryTryCatch (dbP, categoryNum, media, recordNum);
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);
return;
}
/************************************************************
*
* FUNCTION: ToDoImportVEvent
*
* DESCRIPTION: Import a VCal record of type vEvent.
*
* This function doesn't exist on the device because
* the Datebook imports vEvent records. On the emulator
* this function exists for linking completeness.
*
* PARAMETERS:
* dbP - pointer to the database to add the record to
* inputStream - pointer to where to import the record from
* inputFunc - function to get input from the stream
* obeyUniqueIDs - true to obey any unique ids if possible
* beginAlreadyRead - whether the begin statement has been read
*
* RETURNS: true if the input was read
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* roger 9/12/97 Created
*
*************************************************************/
static Boolean ToDoImportVEvent(DmOpenRef UNUSED_PARAM(dbP), UInt16 UNUSED_PARAM(pdiRefNum), PdiReaderType* UNUSED_PARAM(reader),
Boolean UNUSED_PARAM(obeyUniqueIDs), Boolean UNUSED_PARAM(beginAlreadyRead), UInt32 * UNUSED_PARAM(uniqueIDP))
{
return false;
}
/***********************************************************************
*
* FUNCTION: ToDoSetGoToParams
*
* DESCRIPTION: Store the information necessary to navigate to the
* record inserted into the launch code's parameter block.
*
* PARAMETERS: dbP - pointer to the database to add the record to
* exgSocketP - parameter block passed with the launch code
* uniqueID - unique id of the record inserted
*
* RETURNED: nothing
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* art 10/17/97 Created
* ABa 08/18/00 make it public for use in ToDo.c
*
***********************************************************************/
extern void ToDoSetGoToParams (DmOpenRef dbP, ExgSocketPtr exgSocketP, UInt32 uniqueID)
{
UInt16 recordNum;
UInt16 cardNo;
LocalID dbID;
if (! uniqueID) return;
DmOpenDatabaseInfo (dbP, &dbID, NULL, NULL, &cardNo, NULL);
// The this the the first record inserted, save the information
// necessary to navigate to the record.
if (! exgSocketP->goToParams.uniqueID)
{
DmFindRecordByID (dbP, uniqueID, &recordNum);
exgSocketP->goToCreator = sysFileCToDo;
exgSocketP->goToParams.uniqueID = uniqueID;
exgSocketP->goToParams.dbID = dbID;
exgSocketP->goToParams.dbCardNo = cardNo;
exgSocketP->goToParams.recordNum = recordNum;
}
// If we already have a record then make sure the record index
// is still correct. Don't update the index if the record is not
// in your the app's database.
else if (dbID == exgSocketP->goToParams.dbID &&
cardNo == exgSocketP->goToParams.dbCardNo)
{
DmFindRecordByID (dbP, exgSocketP->goToParams.uniqueID, &recordNum);
exgSocketP->goToParams.recordNum = recordNum;
}
}
/***********************************************************************
*
* 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
* ---- ---- -----------
* ??? ??? Created
* art 10/17/97 Added "go to" record logic
* bhall 09/27/99 Now always read until no more data
* (previously datebook called us once per event)
*
***********************************************************************/
extern Err ToDoReceiveData(DmOpenRef dbP, ExgSocketPtr exgSocketP)
{
volatile Err err = 0;
UInt16 pdiRefNum = sysInvalidRefNum;
PdiReaderType* reader;
UDAReaderType* stream;
Boolean loaded;
// accept will open a progress dialog and wait for your receive commands
if ((err = ExgAccept(exgSocketP)) != 0)
return err;
if ((err = PrvPdiLibLoad(&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;
// Catch errors receiving records. The import routine will clean up the
// incomplete record. This routine passes the error to ExgDisconnect
// which displays appropriate ui.
ErrTry
{
// Keep importing records until it can't
while(ToDoImportVCal(dbP, pdiRefNum, reader, false, false, ToDoImportVEvent)){};
}
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)
PrvPdiLibUnload(pdiRefNum, loaded);
ExgDisconnect(exgSocketP, err); // closes transfer dialog
err = errNone; // error was reported, so don't return it
return err;
}
/************************************************************
*
* FUNCTION: ToDoImportVToDo
*
* DESCRIPTION: Import a VCal record of type vToDo
*
* PARAMETERS:
* dbP - pointer to the database to add the record to
* inputStream - pointer to where to import the record from
* inputFunc - function to get input from the stream
* obeyUniqueIDs - true to obey any unique ids if possible
* beginAlreadyRead - whether the begin statement has been read
* uniqueIDP - (returned) id of record inserted.
*
* RETURNS: true if the input was read
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* djk 8/9/97 Created
* art 10/17/97 Added parameter to return unique id
*
*************************************************************/
extern Boolean ToDoImportVToDo(DmOpenRef dbP, UInt16 pdiRefNum, PdiReaderType* reader,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -