Пример #1
0
MojErr MojDbPurgeTest::run()
{
	MojDb db;
	MojErr err = db.open(MojDbTestDir);
	MojTestErrCheck(err);

	// put type
	MojObject obj;
	err = obj.fromJson(MojKindStr);
	MojTestErrCheck(err);
	err = db.putKind(obj);
	MojTestErrCheck(err);

	MojObject revNums[10];
	MojObject ids[10];
	//put 10 objects in the db
	for(int i = 0; i < 10; i++) {
		err = obj.fromJson(MojTestObjStr1);
		MojTestErrCheck(err);
		err = db.put(obj);
		MojTestErrCheck(err);
		// get _rev and id
		MojObject rev;
		err = obj.getRequired(MojDb::RevKey, rev);
		MojTestErrCheck(err);
		revNums[i] = rev;
		MojObject id;
		err = obj.getRequired(MojDb::IdKey, id);
		MojTestErrCheck(err);
		ids[i] = id;
	}

	//purge now, there are no RevTimestamp entries
	MojUInt32 count = 0;
	err = db.purge(count, 30);
	MojTestErrCheck(err);

	err = checkObjectsPurged(db, count, 0, 10, 1, -1);
	MojTestErrCheck(err);

	//create a RevTimestamp entry - that's not more than PurgeNumDays days ago
	MojTime time;
	err = MojGetCurrentTime(time);
	MojTestErrCheck(err);
	err = createRevTimestamp(db, revNums[0], time.microsecs());
	MojTestErrCheck(err);

	//purge now, there are no RevTimestamp entries that are more than
	//PurgeNumDays ago, so nothing should be purged
	count = 0;
	err = db.purge(count, 30);
	MojTestErrCheck(err);

	err = checkObjectsPurged(db, count, 0, 10, 3, -1);
	MojTestErrCheck(err);

	//create a RevTimestamp entry for more than PurgeNumDays days ago
	err = MojGetCurrentTime(time);
	MojTestErrCheck(err);
	err = createRevTimestamp(db, revNums[9], time.microsecs() - (((MojInt64)40) * MojTime::UnitsPerDay));
	MojTestErrCheck(err);

	//purge now, since nothing has been deleted, nothing should be purged,
	//but the RevTimestamp object should be deleted
	count = 0;
	err = db.purge(count, 30);
	MojTestErrCheck(err);

	err = checkObjectsPurged(db, count, 0, 10, 4, -1);
	MojTestErrCheck(err);

	//delete something - this will set its revision number higher
	bool found;
	err = db.del(ids[0], found);
	MojTestErrCheck(err);
	MojTestAssert(found == true);

	//purge now, since nothing has been deleted prior to the revision
	//number, nothing should be purged
	count = 0;
	err = db.purge(count, 30);
	MojTestErrCheck(err);

	err = checkObjectsPurged(db, count, 0, 9, 5, -1);
	MojTestErrCheck(err);

	//delete another object
	err = db.del(ids[1], found);
	MojTestErrCheck(err);
	MojTestAssert(found == true);

	//create a RevTimestamp entry for more than PurgeNumDays days ago,
	//with the rev number of the 1st obj we deleted
	MojDbQuery query;
	err = query.from(_T("PurgeTest:1"));
	MojTestErrCheck(err);
	err = query.where(MojDb::IdKey, MojDbQuery::OpEq, ids[0]);
	MojTestErrCheck(err);
	err = query.includeDeleted();
	MojTestErrCheck(err);

	MojDbCursor cursor;
	err = db.find(query, cursor);
	MojTestErrCheck(err);

	MojObject objFromDb;
	err = cursor.get(objFromDb, found);
	MojTestErrCheck(err);
	err = cursor.close();
	MojTestErrCheck(err);
	MojTestAssert(found == true);

	MojObject revFromDb;
	err = objFromDb.getRequired(MojDb::RevKey, revFromDb);
	MojTestErrCheck(err);

	err = MojGetCurrentTime(time);
	MojTestErrCheck(err);
	err = createRevTimestamp(db, revFromDb, time.microsecs() - (((MojInt64)35) * MojTime::UnitsPerDay));
	MojTestErrCheck(err);

	//now purge, only id[0] should be purged
	count = 0;
	err = db.purge(count, 30);
	MojTestErrCheck(err);

	err = checkObjectsPurged(db, count, 1, 8, 6, revFromDb);
	MojTestErrCheck(err);

	//TODO 2.12.10 - this test does not pass yet, we need to fix calling delKind after a purge
	//err = delKindTest(db);
	//MojTestErrCheck(err);

	err = db.close();
	MojTestErrCheck(err);

	return MojErrNone;
}
MojErr TrimFolderEmailsCommand::GetLocalEmailsResponse(MojObject& response, MojErr err)
{
	try {
		// Check database response
		ErrorToException(err);

		MojObject results;
		err = response.getRequired("results", results);
		ErrorToException(err);

		MojObject::ArrayIterator it;
		err = results.arrayBegin(it);
		ErrorToException(err);

		for (; it != results.arrayEnd(); ++it) {
			MojObject& emailObj = *it;
			MojErr err;

			MojObject id;
			err = emailObj.getRequired(PopEmailAdapter::ID, id);
			ErrorToException(err);

			MojString uid;
			err = emailObj.getRequired(PopEmailAdapter::SERVER_UID, uid);
			ErrorToException(err);
			std::string uidStr(uid);

			MojInt64 timestamp;
			err = emailObj.getRequired(EmailSchema::TIMESTAMP, timestamp);

			// add email ID to the list of IDs to be deleted
			m_idsToTrim.push(id);
			// move trimmed emails to old emails' cache so that they won't be
			// added in the next sync
			m_uidCache.GetOldEmailsCache().AddToCache(uid.data(), timestamp);
			m_uidCache.GetOldEmailsCache().SetChanged(true);

			// decrement the number of emails to be trimmed
			if (--m_numberToTrim == 0) {
				break;
			}
		}

		bool hasMore = DatabaseAdapter::GetNextPage(response, m_localEmailsPage);
		if(m_numberToTrim > 0 && hasMore) {
			// Get next batch of emails to be deleted
			MojLogInfo(m_log, "getting another batch of local emails");
			GetLocalEmails();
		} else {
			MojLogInfo(m_log, "Delete local emails cache");
			DeleteLocalEmails();
		}
	} catch(const std::exception& e) {
		MojLogError(m_log, "Failed to get local emails: %s", e.what());
		Failure(e);
	} catch(...) {
		MojLogError(m_log, "Uncaught exception %s", __PRETTY_FUNCTION__);
		MailException exc("Unable to get local emails", __FILE__, __LINE__);
		Failure(exc);
	}

	return MojErrNone;
}
Пример #3
0
void EmailAdapter::ParseDatabaseObject(const MojObject& obj, Email& email)
{
	MojErr err;
	
	MojObject folderId;
	err = obj.getRequired(FOLDER_ID, folderId);
	ErrorToException(err);
	email.SetFolderId(folderId);
	
	MojString subject;
	err = obj.getRequired(SUBJECT, subject);
	ErrorToException(err);
	email.SetSubject( std::string(subject) );
	
	MojObject fromAddress;
	err = obj.getRequired(FROM, fromAddress);
	ErrorToException(err);
	email.SetFrom( ParseAddress(fromAddress) );
	
	// Optional replyTo address
	MojObject replyTo;
	if(obj.get(REPLY_TO, replyTo) && !replyTo.null()) {
		email.SetReplyTo( ParseAddress(replyTo) );
	}

	MojInt64 timestamp;
	err = obj.getRequired(TIMESTAMP, timestamp);
	ErrorToException(err);
	email.SetDateReceived(timestamp);
	
	// Parse recipients
	MojObject recipients;
	err = obj.getRequired(RECIPIENTS, recipients);
	ErrorToException(err);
	ParseRecipients(recipients, email);
	
	// Parse flags
	MojObject flags;
	if (obj.get(FLAGS, flags)) {
		ParseFlags(flags, email);
	}

	// Parse parts
	MojObject parts;
	err = obj.getRequired(PARTS, parts);
	ErrorToException(err);

	EmailPartList partList;
	ParseParts(parts, partList);
	email.SetPartList(partList);

	MojObject originalMsgId;
	if (obj.get(ORIGINAL_MSG_ID, originalMsgId)) {
		email.SetOriginalMsgId(originalMsgId);
	}

	MojString draftType;
	bool hasDraftType = false;
	err = obj.get(DRAFT_TYPE, draftType, hasDraftType);
	ErrorToException(err);
	if (hasDraftType) {
		email.SetDraftType( ParseDraftType(draftType) );
	}

	MojString priority;
	bool hasPriority = false;
	err = obj.get(PRIORITY, priority, hasPriority);
	ErrorToException(err);
	// If no priority exists, this will default to normal
	email.SetPriority(ParsePriority(priority));

	email.SetMessageId( DatabaseAdapter::GetOptionalString(obj, MESSAGE_ID) );
	email.SetInReplyTo( DatabaseAdapter::GetOptionalString(obj, IN_REPLY_TO) );

	// SendStatus
	// NOTE: This is not being serialized back to the database in SerializeToDatabaseObject
	MojObject sendStatus;
	if (obj.get(SEND_STATUS, sendStatus)) {
		bool isSent = false;
		if (sendStatus.get(SendStatus::SENT, isSent)) {
			email.SetSent(isSent);
		}
		bool hasFatalError = false;
		if (sendStatus.get(SendStatus::FATAL_ERROR, hasFatalError)) {
			email.SetHasFatalError(hasFatalError);
		}
		MojInt64 retryCount;
		if (sendStatus.get(SendStatus::RETRY_COUNT, retryCount)) {
			email.SetRetryCount(retryCount);
		}
		MojObject sendError;
		if (sendStatus.get(SendStatus::ERROR, sendError)) {
			MojObject errorCode;
			if (sendError.get(SendStatusError::ERROR_CODE, errorCode) && !errorCode.null() && !errorCode.undefined()) {
				email.SetSendError(static_cast<MailError::ErrorCode>(errorCode.intValue()));
			}
		}
	}
}
/*
 * Send one IMCommand that has handler set to transport
 *
 * errors returned up to OutgoingIMCommandHandler
 *
 *
 * @param imCmd - imCommand that was read out of the DB with handler set to transport
 {
   "id"      : "ImCommand",
   "type"    : "object",
   "properties" : {
      "command"       : {"type"        : "string",
                         "enum"        : ["blockBuddy","deleteBuddy","sendBuddyInvite","receivedBuddyInvite","createChatGroup","inviteToGroup","leaveGroup"],
                         "description" : "The command to be processed"},
      "params"        : {"type"        : "any",
                         "description" : "Parameters associated with the command are stored here."}
      "handler"       : {"type"        : "string",
                         "enum"        : ["transport","application"],
                         "description" : "Who is responsible for handling the command"},
      "targetUsername"  : {"type"        : "string",
                         "description" : "The buddyname the command will act on"},
      "fromUsername"  : {"type"        : "string",
                         "description" : "The username that originated the command"},
      "serviceName"   : {"type"        : "string",
                         "description" : "Name of originating service (see IMAddress of contacts load library*)."}
      }
 * }
 */
MojErr SendOneCommandHandler::doSend(const MojObject imCmd) {

	IMServiceHandler::logMojObjectJsonString(_T("send command: %s"),imCmd);
	MojString command;
	LibpurpleAdapter::SendResult retVal = LibpurpleAdapter::SENT;
	bool found = false;

	MojErr err = imCmd.get(MOJDB_COMMAND, command, found);
	MojErrCheck(err);

	// serviceName
	err = imCmd.get(MOJDB_SERVICE_NAME, m_serviceName, found);
	MojErrCheck(err);

	// get the id so we can update the status in  the DB after sending
	err = imCmd.getRequired(MOJDB_ID, m_currentCmdDbId);
	MojErrCheck(err);

	// for receiving invite, the user account and remote user are reversed: targetUsername is us and the fromUsername is the remote buddy
	if (0 == command.compare(_T("receivedBuddyInvite"))) {
		// username of current account
		err = imCmd.get(MOJDB_FROM_USER, m_buddyName, found);
		MojErrCheck(err);

		// buddy / remote user
		err = imCmd.get(MOJODB_TARGET_USER, m_username, found);
		MojErrCheck(err);
	}
	else {
		// username of current account
		err = imCmd.get(MOJDB_FROM_USER, m_username, found);
		MojErrCheck(err);

		// buddy / remote user
		err = imCmd.get(MOJODB_TARGET_USER, m_buddyName, found);
		MojErrCheck(err);
	}

	// which command?
	if (0 == command.compare(_T("blockBuddy"))) {
		retVal = blockBuddy(imCmd);
	}
	else if (0 == command.compare(_T("deleteBuddy"))) {
		retVal = removeBuddy(imCmd);
	}
	else if (0 == command.compare(_T("sendBuddyInvite"))) {
		retVal = inviteBuddy(imCmd);
	}
	else if (0 == command.compare(_T("receivedBuddyInvite"))) {
		retVal = receivedBuddyInvite(imCmd);
	}
	else {
		MojLogError(IMServiceApp::s_log, _T("doSend: unknown command %s"), command.data());
		retVal = LibpurpleAdapter::SEND_FAILED;
	}

	// we can't just delete the command if the user is not logged on...
	// need to save command in "waiting" state waiting for user to login
	if (LibpurpleAdapter::USER_NOT_LOGGED_IN == retVal) {
		// user not logged in - put in queued state
		MojLogError(IMServiceApp::s_log, _T("doSend - can't process command - user not logged in. Waiting for connection"));
		MojObject propObject;
		propObject.putString(MOJDB_STATUS, IMMessage::statusStrings[WaitingForConnection]);

		// id to update
		propObject.putString(MOJDB_ID, m_currentCmdDbId);

		// save the new fields - call merge
		err = m_dbClient.merge(this->m_imSaveCommandSlot, propObject);
		if (err) {
			MojLogError(IMServiceApp::s_log, _T("doSend - DB merge command failed. err %d, DB id %s: "), err, m_currentCmdDbId.data() );
		}
	}
	else {
		// delete command so we don't keep processing it
		// put id in an array
		MojObject idsToDelete;  // array
		err = idsToDelete.push(m_currentCmdDbId);

		// luna://com.palm.db/del '{"ids":[2]}'
		IMServiceHandler::logMojObjectJsonString(_T("deleting imcommand: %s"), idsToDelete);
		err = m_dbClient.del(this->m_imDeleteCommandSlot, idsToDelete.arrayBegin(), idsToDelete.arrayEnd());

		if (err) {
			MojLogError(IMServiceApp::s_log, _T("doSend - DB del command failed. err %d, DB id %s: "), err, m_currentCmdDbId.data() );
		}
	}

	if (LibpurpleAdapter::SENT != retVal) {
		// something went wrong - nothing more we can do
		MojLogError(IMServiceApp::s_log, _T("doSend: command failed"));
		m_outgoingIMHandler->messageFinished();

	}

	return MojErrNone;
}
Пример #5
0
/**
 * Parse two database objects into an ImapAccount
 *
 * @param in			com.palm.mail.account database object
 * @param transportIn	com.palm.imap.account database object
 * @param out			ImapAccount
 */
void ImapAccountAdapter::GetImapAccount(const MojObject& in, const MojObject& transportIn, ImapAccount& out)
{
	MojObject id;
	MojErr err = in.getRequired(ID, id);
	ErrorToException(err);
	out.SetId(id);

	// Template from account object
	MojString templateId;
	bool hasTemplateId = false;
	err = in.get(TEMPLATEID, templateId, hasTemplateId); // make required later
	ErrorToException(err);
	if(hasTemplateId)
	{
		out.SetTemplateId(templateId.data());
	}
	
	boost::shared_ptr<ImapLoginSettings> loginSettings(new ImapLoginSettings());

	// Username from account object (this is always the email address)
	MojString username;
	in.getRequired(USERNAME, username);
	ErrorToException(err);

	loginSettings->SetUsername(username.data());

	// Read server settings
	ParseLoginConfig(transportIn, *loginSettings);

	// Store updated server settings on account
	out.SetLoginSettings(loginSettings);

	int syncFrequencyMin;
	err = transportIn.getRequired(EmailAccountAdapter::SYNC_FREQUENCY_MINS, syncFrequencyMin);
	ErrorToException(err);
	out.SetSyncFrequencyMins(syncFrequencyMin);

	int syncWindowDays;
	err = transportIn.getRequired(EmailAccountAdapter::SYNC_WINDOW_DAYS, syncWindowDays);
	ErrorToException(err);
	out.SetSyncWindowDays(syncWindowDays);

	MojInt64 rev;
	err = transportIn.getRequired(REV, rev);
	ErrorToException(err);
	out.SetRevision(rev);

	// Retrieve the optional error status
	MojObject errorObj;
	if(transportIn.get(EmailAccountAdapter::ERROR, errorObj))
	{
		EmailAccount::AccountError accountError;
		EmailAccountAdapter::ParseErrorInfo(errorObj, accountError);

		out.SetError(accountError);
	}

	// Compatibility/workaround options
	bool enableCompress = DatabaseAdapter::GetOptionalBool(transportIn, ENABLE_COMPRESS, ImapConfig::GetConfig().GetEnableCompress());
	bool enableExpunge = DatabaseAdapter::GetOptionalBool(transportIn, ENABLE_EXPUNGE, true);

	out.SetEnableCompression(enableCompress);
	out.SetEnableExpunge(enableExpunge);

	// Read special folders
	EmailAccountAdapter::ParseSpecialFolders(transportIn, out);

	// Read retry status
	EmailAccountAdapter::ParseAccountRetryStatus(transportIn, out);

	// Root folder prefix
	bool hasRootFolder = false;
	MojString rootFolder;
	err = transportIn.get(ROOT_FOLDER, rootFolder, hasRootFolder);
	ErrorToException(err);

	if(hasRootFolder) {
		out.SetNamespaceRoot( string(rootFolder.data()) );
	}
}
Пример #6
0
MojErr MojDbRevTest::run()
{
	MojDb db;
	MojErr err = db.open(MojDbTestDir);
	MojTestErrCheck(err);

	// put type
	MojObject obj;
	err = obj.fromJson(MojKindStr);
	MojTestErrCheck(err);
	// put obj
	err = db.putKind(obj);
	MojTestErrCheck(err);
	err = obj.fromJson(MojTestObjStr1);
	MojTestErrCheck(err);
	err = db.put(obj);
	MojTestErrCheck(err);
	MojObject id;
	err = obj.getRequired(MojDb::IdKey, id);
	MojTestErrCheck(err);
	// get obj and verify rev eq
	MojObject rev;
	err = obj.getRequired(MojDb::RevKey, rev);
	MojTestErrCheck(err);
	err = checkRevEq(db, id, rev);
	MojTestErrCheck(err);
	// put identical obj and verify rev not changed
	err = db.put(obj);
	MojTestErrCheck(err);
	err = checkRevEq(db, id, rev);
	MojTestErrCheck(err);
	// put with changed prop and verify rev gt
	err = obj.fromJson(MojTestObjStr2);
	MojTestErrCheck(err);
	err = obj.put(MojDb::IdKey, id);
	MojTestErrCheck(err);
	err = db.put(obj); // this put will fail because we haven't included a rev
	MojTestErrExpected(err, MojErrDbRevNotSpecified);
	bool found = false;
	err = db.del(id, found); // verify that we can put without a rev if the object is deleted
	MojTestErrCheck(err);
	MojTestAssert(found);
	err = db.put(obj);
	MojTestErrCheck(err);
	err = obj.getRequired(MojDb::RevKey, rev);
	MojTestErrCheck(err);
	err = obj.put(MojDb::RevKey, 1);
	MojTestErrCheck(err);
	err = db.put(obj); // this put will fail because the revision num is lower
	MojTestErrExpected(err, MojErrDbRevisionMismatch);
	err = obj.put(MojDb::RevKey, rev);
	MojTestErrCheck(err);
	err = db.put(obj); // now this should succeed
	MojTestErrCheck(err);
	// merge with unchanged prop and verify rev not changed
	err = obj.fromJson(MojTestObjStr3);
	MojTestErrCheck(err);
	err = obj.put(MojDb::IdKey, id);
	MojTestErrCheck(err);
	err = db.merge(obj);
	MojTestErrCheck(err);
	err = checkRevEq(db, id, rev);
	MojTestErrCheck(err);
	// merge with changed prop and verify rev gt
	err = obj.fromJson(MojTestObjStr4);
	MojTestErrCheck(err);
	err = obj.put(MojDb::IdKey, id);
	MojTestErrCheck(err);
	err = db.merge(obj);
	MojTestErrCheck(err);
	err = checkRevGt(db, id, rev);
	MojTestErrCheck(err);
	// query merge with unchanged prop and verify rev not changed
	MojDbQuery query;
	err = query.from("RevTest:1");
	MojTestErrCheck(err);
	err = obj.fromJson(MojTestObjStr4);
	MojTestErrCheck(err);
	MojUInt32 count = 0;
	err = db.merge(query, obj, count);
	MojTestErrCheck(err);
	MojTestAssert(count == 1);
	err = checkRevEq(db, id, rev);
	MojTestErrCheck(err);
	// query merge with changed prop and verify rev gt
	err = obj.fromJson(MojTestObjStr3);
	MojTestErrCheck(err);
	err = db.merge(query, obj, count);
	MojTestErrCheck(err);
	MojTestAssert(count == 1);
	err = checkRevGt(db, id, rev);
	MojTestErrCheck(err);
	// del verify rev gt
	err = db.del(id, found);
	MojTestErrCheck(err);
	MojTestAssert(found);
	err = checkRevGt(db, id, rev);
	MojTestErrCheck(err);
	// del again and verify rev not changed
	err = db.del(id, found);
	MojTestErrCheck(err);
	MojTestAssert(found);
	err = checkRevEq(db, id, rev);
	MojTestErrCheck(err);
	// undel and verify rev gt
	err = obj.fromJson(MojTestObjStr5);
	MojTestErrCheck(err);
	err = obj.put(MojDb::IdKey, id);
	MojTestErrCheck(err);
	err = db.merge(obj);
	MojTestErrCheck(err);
	err = checkRevGt(db, id, rev);
	MojTestErrCheck(err);
	// query del and verify rev gt
	err = db.del(query, count);
	MojTestErrCheck(err);
	MojTestAssert(count == 1);
	err = checkRevGt(db, id, rev);
	MojTestErrCheck(err);

	err = db.close();
	MojTestErrCheck(err);

	return MojErrNone;
}
Пример #7
0
MojErr MojDbQuery::fromObject(const MojObject& obj)
{
	// TODO: validate against query schema

	bool found;
	MojErr err;
	MojObject array;
	MojString str;

	// distinct
	found = false;
	err = obj.get(DistinctKey, str, found);
	MojErrCheck(err);
	if (found) {
		err = distinct(str);
		MojErrCheck(err);
		// if "distinct" is set, force "distinct" column into "select".
		err = select(str);
		MojErrCheck(err);
		// order
		err = order(str);
		MojErrCheck(err);
	} else {
		// select
		if (obj.get(SelectKey, array)) {
			if(array.empty()) {
				MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: select clause but no selected properties"));
			}
			MojObject prop;
			MojSize i = 0;
			while (array.at(i++, prop)) {
				MojErr err = prop.stringValue(str);
				MojErrCheck(err);
				err = select(str);
				MojErrCheck(err);
			}
		}
		// order
		found = false;
		err = obj.get(OrderByKey, str, found);
		MojErrCheck(err);
		if (found) {
			err = order(str);
			MojErrCheck(err);
		}
	}
	// from
	err = obj.getRequired(FromKey, str);
	MojErrCheck(err);
	err = from(str);
	MojErrCheck(err);
	// where
	if (obj.get(WhereKey, array)) {
		err = addClauses(m_whereClauses, array);
		MojErrCheck(err);
	}
	// filter
	if (obj.get(FilterKey, array)) {
		err = addClauses(m_filterClauses, array);
		MojErrCheck(err);
	}
	// desc
	bool descVal;
	if (obj.get(DescKey, descVal)) {
		desc(descVal);
	}
	// limit
	MojInt64 lim;
	if (obj.get(LimitKey, lim)) {
		if (lim < 0)
			MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: negative query limit"));
	} else {
		lim = LimitDefault;
	}
	limit((MojUInt32) lim);
	// page
	MojObject pageObj;
	if (obj.get(PageKey, pageObj)) {
		Page pagec;
		err = pagec.fromObject(pageObj);
		MojErrCheck(err);
		page(pagec);
	}
	bool incDel = false;
	if (obj.get(IncludeDeletedKey, incDel) && incDel) {
		err = includeDeleted();
		MojErrCheck(err);
	}
	return MojErrNone;
}
MojErr OnEnabledHandler::findImLoginStateResult(MojObject& payload, MojErr err)
{
	MojLogTrace(IMServiceApp::s_log);

	if (err != MojErrNone) {
		MojString error;
		MojErrToString(err, error);
		MojLogCritical(IMServiceApp::s_log, _T("findImLoginStateResult failed: error %d - %s"), err, error.data());
	}
	else {
		// "results" in result
		MojObject results;
		payload.get(_T("results"), results);

		// check to see if array is empty - normally it will be if this is a newly created account. There should never be more than 1 item here
		if (!results.empty()){

			IMServiceHandler::logMojObjectJsonString(_T("findImLoginStateResult found existing imLoginState record: %s"), payload);

			// if there is a record already, make sure the account id matches.
			MojObject loginState;
			MojObject::ConstArrayIterator itr = results.arrayBegin();
			bool foundOne = false;
			while (itr != results.arrayEnd()) {
				if (foundOne) {
					MojLogError(IMServiceApp::s_log,
							_T("findImLoginStateResult: found more than one ImLoginState with same username/serviceName - using the first one"));
					break;
				}
				loginState = *itr;
				foundOne = true;
				itr++;
			}

			MojString accountId;
			MojErr err = loginState.getRequired("accountId", accountId);
			if (err) {
				MojLogError(IMServiceApp::s_log, _T("findImLoginStateResult: missing accountId in loginState entry"));
			}
			if (0 != accountId.compare(m_accountId)) {
				MojLogError(IMServiceApp::s_log, _T("findImLoginStateResult: existing loginState record does not have matching account id. accountId = %s"), accountId.data());

				// delete this record
				MojObject idsToDelete;
				MojString dbId;
				err = loginState.getRequired("_id", dbId);
				if (err) {
					MojLogError(IMServiceApp::s_log, _T("findImLoginStateResult: missing dbId in loginState entry"));
				}
				else {
				    idsToDelete.push(dbId);

					// luna://com.palm.db/del '{"ids":[2]}'
					MojLogInfo(IMServiceApp::s_log, _T("findImLoginStateResult: deleting loginState entry id: %s"), dbId.data());
					err = m_dbClient.del(this->m_deleteImLoginStateSlot, idsToDelete.arrayBegin(), idsToDelete.arrayEnd());
					if (err != MojErrNone) {
						MojString error;
						MojErrToString(err, error);
						MojLogError(IMServiceApp::s_log, _T("findImLoginStateResult: db.del() failed: error %d - %s"), err, error.data());
					}
				}
			}
			// if the account id matches, leave the old record and we are done
			else return MojErrNone;
		}

		// no existing record found or the old one was deleted - create a new one
		MojLogInfo(IMServiceApp::s_log, _T("findImLoginStateResult: no matching loginState record found for %s, %s. creating a new one"), m_username.data(), m_serviceName.data());
		MojObject imLoginState;
		imLoginState.putString(_T("_kind"), IM_LOGINSTATE_KIND);
		imLoginState.put(_T("accountId"), m_accountId);
		imLoginState.put(_T("serviceName"), m_serviceName);
		imLoginState.put(_T("username"), m_username);
        imLoginState.put(_T("capabilityId"), m_capabilityProviderId);
		imLoginState.putString(_T("state"), LOGIN_STATE_OFFLINE);
		imLoginState.putInt(_T("availability"), PalmAvailability::ONLINE); //default to online so we automatically login at first
        imLoginState.put(_T("config"), m_config);
		MojErr err = m_dbClient.put(m_addImLoginStateSlot, imLoginState);
		if (err != MojErrNone) {
			MojString error;
			MojErrToString(err, error);
			MojLogError(IMServiceApp::s_log, _T("findImLoginStateResult: db.put() failed: error %d - %s"), err, error.data());
		}

	}
	return err;
}
Пример #9
0
MojErr MojDb::purgeImpl(MojObject& obj, MojUInt32& countOut, MojDbReq& req)
{
	MojLogTrace(s_log);

	MojObject val;
	MojErr err = obj.getRequired(RevNumKey, val);
	MojErrCheck(err);
	MojObject timestamp;
	err = obj.getRequired(TimestampKey, timestamp);
	MojErrCheck(err);

	// purge all objects that were deleted on or prior to this rev num

	// query for objects in two passes - once where backup is true and once where backup is false
	MojDbQuery objQuery;
	err = objQuery.from(MojDbKindEngine::RootKindId);
	MojErrCheck(err);
	err = objQuery.where(DelKey, MojDbQuery::OpEq, true);
	MojErrCheck(err);
	err = objQuery.where(SyncKey, MojDbQuery::OpEq, true);
	MojErrCheck(err);
	err = objQuery.where(RevKey, MojDbQuery::OpLessThanEq, val);
	MojErrCheck(err);

	MojUInt32 backupCount = 0;
	req.autobatch(true);
	req.fixmode(true);
	objQuery.limit(AutoBatchSize);
	err = delImpl(objQuery, backupCount, req, FlagPurge);
	MojErrCheck(err);

	MojDbQuery objQuery2;
	err = objQuery2.from(MojDbKindEngine::RootKindId);
	MojErrCheck(err);
	err = objQuery2.where(DelKey, MojDbQuery::OpEq, true);
	MojErrCheck(err);
	err = objQuery2.where(SyncKey, MojDbQuery::OpEq, false);
	MojErrCheck(err);
	err = objQuery2.where(RevKey, MojDbQuery::OpLessThanEq, val);
	MojErrCheck(err);
	MojUInt32 count = 0;
	MojUInt32 batchRemain = 0;
	if (backupCount <= AutoBatchSize)
		batchRemain = AutoBatchSize - backupCount;
	req.autobatch(true);		// enable auto batch
	req.fixmode(true);		// force deletion of bad entries

	if (batchRemain > 0) {
		objQuery2.limit(batchRemain);
		err = delImpl(objQuery2, count, req, FlagPurge);
		MojErrCheck(err);
	}

	countOut = count + backupCount;

	req.autobatch(false);

	// if we actually deleted objects, store this rev num as the last purge rev
	if (countOut > 0) {
		err = updateState(LastPurgedRevKey, val, req);
		MojErrCheck(err);
	}

	// delete all the RevTimestamp entries prior to this one
	MojDbQuery revTimestampQuery;
	err = revTimestampQuery.from(MojDbKindEngine::RevTimestampId);
	MojErrCheck(err);
	err = revTimestampQuery.where(TimestampKey, MojDbQuery::OpLessThanEq, timestamp);
	MojErrCheck(err);

	count = 0;
	err = delImpl(revTimestampQuery, count, req, FlagPurge);
	MojErrCheck(err);


	return MojErrNone;
}
Пример #10
0
MojErr MojDbKind::configure(const MojObject& obj, const KindMap& map, const MojString& locale, MojDbReq& req)
{
	MojLogTrace(s_log);

	// get owner before checking permissions
	MojString owner;
	MojErr err = obj.getRequired(OwnerKey, owner);
	MojErrCheck(err);
	// only admin can change owner
	if (!m_owner.empty() && m_owner != owner && !req.admin()) {
		err = deny(req);
		MojErrCheck(err);
	}
	m_owner = owner;

	err = checkPermission(OpKindUpdate, req);
	MojErrCheck(err);

	// schema
	MojObject schema;
	if (obj.get(SchemaKey,schema)) {
		err = m_schema.fromObject(schema);
		MojErrCheck(err);
	}
	// supers
	StringVec superIds;
	MojObject supers;
	if (obj.get(ExtendsKey, supers)) {
		MojObject::ConstArrayIterator end = supers.arrayEnd();
		for (MojObject::ConstArrayIterator i = supers.arrayBegin(); i != end; ++i) {
			MojString str;
			err = i->stringValue(str);
			MojErrCheck(err);
			err = superIds.push(str);
			MojErrCheck(err);
		}
	}
	// backup
	bool backup = false;
	if (obj.get(SyncKey, backup))
		m_backup = backup;
	bool updating = !m_obj.undefined();

	// load state
	m_state.reset(new MojDbKindState(m_id, m_kindEngine));
	MojAllocCheck(m_state.get());
	err = m_state->init(m_schema.strings(), req);
	MojErrCheck(err);
	// indexes
	err = configureIndexes(obj, locale, req);
	MojErrCheck(err);
	// supers
	err = updateSupers(map, superIds, updating, req);
	MojErrCheck(err);
	// revision sets
	err = configureRevSets(obj);
	MojErrCheck(err);

	// keep a copy of obj
	m_obj = obj;

	return MojErrNone;
}
Пример #11
0
MojErr MojDb::dumpImpl(MojFile& file, bool backup, bool incDel, const MojObject& revParam, const MojObject& delRevParam, bool skipKinds, MojUInt32& countOut, MojDbReq& req,
		MojObject* response, const MojChar* keyName, MojSize& bytesWritten, MojSize& warns, MojUInt32 maxBytes)
{
	// query for objects, adding the backup key and rev key if necessary
	MojDbQuery query;
	MojErr err = query.from(MojDbKindEngine::RootKindId);
	MojErrCheck(err);
	err = query.where(MojDb::DelKey, MojDbQuery::OpEq, incDel);
	MojErrCheck(err);
	if (backup) {
		err = query.where(MojDb::SyncKey, MojDbQuery::OpEq, true);
		MojErrCheck(err);
		if (incDel) {
			err = query.where(MojDb::RevKey, MojDbQuery::OpGreaterThan, delRevParam);
			MojErrCheck(err);
		} else {
			err = query.where(MojDb::RevKey, MojDbQuery::OpGreaterThan, revParam);
			MojErrCheck(err);
		}
	}

	MojDbCursor cursor;
	err = findImpl(query, cursor, NULL, req, OpRead);
	MojErrCheck(err);
	warns = 0;

	MojObject curRev;
	for(;;) {
		bool found = false;
		MojObject obj;
		err = cursor.get(obj, found);
		// So that we can get as much data as possible from a corrupt database
		// We simply skip ghost keys and continue
		if (err == MojErrInternalIndexOnFind) {
			warns++;
			continue;
		}
		MojErrCheck(err);
		if (!found)
			break;

		if (skipKinds) {
			MojString kind;
			err = obj.getRequired(KindKey, kind);
			MojErrCheck(err);
			if (kind == MojDbKindEngine::KindKindId) {
				continue;
			}
		}

		// write out each object, if the backup is full, insert the appropriate incremental key
		err = dumpObj(file, obj, bytesWritten, maxBytes);
		MojErrCatch(err, MojErrDbBackupFull) {
			if (response) {
				MojErr errBackup = MojErrNone;
				if (!curRev.undefined()) {
					errBackup = insertIncrementalKey(*response, keyName, curRev);
					MojErrCheck(errBackup);
				} else {
					errBackup = insertIncrementalKey(*response, keyName, incDel ? delRevParam: revParam);
					MojErrCheck(errBackup);
				}
				errBackup = handleBackupFull(revParam, delRevParam, *response, keyName);
				MojErrCheck(errBackup);
			}
			return MojErrNone;
		}
		MojErrCheck(err);
		err = obj.getRequired(MojDb::RevKey, curRev);
		MojErrCheck(err);
		countOut++;
	}
	err = cursor.close();
	MojErrCheck(err);

    if (warns > 0) {
        MojLogWarning(s_log, _T("Finished Backup with %d warnings \n"), (int)warns);
    } else {
        MojLogDebug(s_log, _T("Finished Backup with no warnings \n"));
    }

	// construct the next incremental key
	if (response && !curRev.undefined()) {
		err = insertIncrementalKey(*response, keyName, curRev);
		MojErrCheck(err);
	}
	return MojErrNone;
}
MojErr ReconcileEmailsCommand::GetLocalEmailsResponse(MojObject& response, MojErr err)
{
	try {
		MojLogDebug(m_log, "Got local emails response: %s", AsJsonString(response).c_str());

		// Check database response
		ErrorToException(err);

		MojObject results;
		err = response.getRequired("results", results);
		ErrorToException(err);

		MojObject::ArrayIterator it;
		err = results.arrayBegin(it);
		ErrorToException(err);

		for (; it != results.arrayEnd(); ++it) {
			MojObject& emailObj = *it;
			MojErr err;

			MojObject id;
			err = emailObj.getRequired(PopEmailAdapter::ID, id);
			ErrorToException(err);

			MojString uid;
			err = emailObj.getRequired(PopEmailAdapter::SERVER_UID, uid);
			ErrorToException(err);
			std::string uidStr(uid);

			MojInt64 timestamp;
			err = emailObj.getRequired(EmailSchema::TIMESTAMP, timestamp);

			if (!m_uidMap->HasUid(uidStr)) {
				// email is not found in server
				if (!m_account->IsDeleteOnDevice()) {
					// if the user chooses not to delete emails on device that
					// have been deleted from the server, that means these emails
					// won't been deleted.  So we need to include these emails as wells.
					m_messageCount++;
				}
			
				// TODO: need to handle the case when an email is moved from other
				// folders into inbox.  May add a virtual flag in POP email to indicate
				// that the email has been locally move into inbox.
				m_serverDeletedEmailIds.push(id);
			} else {
				boost::shared_ptr<ReconcileInfo> info = m_reconcileUidMap[uidStr];
				if (timestamp < m_cutOffTime) {
					// email is beyond sync window

					// add id to the array of IDs that will be deleted soon
					m_oldEmailIds.push(id);
					// add this old email into old emails' cache
					m_uidCache.GetOldEmailsCache().AddToCache(std::string(uid), timestamp);
					m_uidCache.GetOldEmailsCache().SetChanged(true);

					// mark reconcile info as old email
					info->SetStatus(Status_Old_Email);
					info->SetTimestamp(timestamp);
				} else {
					// email is still within sync window
				
					// mark reconcile info as downloaded
					info->SetStatus(Status_Downloaded);
					info->SetTimestamp(timestamp);

					if (timestamp > m_latestEmailTimestamp) {
						m_latestEmailTimestamp = timestamp;
					}

					// keep track of how many emails will be remained in the inbox
					m_messageCount++;
				}
			}
		}

		bool hasMore = DatabaseAdapter::GetNextPage(response, m_localEmailsPage);
		if(hasMore) {
			// Get next batch of emails
			MojLogDebug(m_log, "getting another batch of local emails");
			GetLocalEmails();
		} else {
			MojLogDebug(m_log, "Got local deleted emails cache");
			GetLocalDeletedEmails();
		}
	} catch(const std::exception& e) {
		MojLogError(m_log, "Failed to get local emails: %s", e.what());
		Failure(e);
	} catch(...) {
		MojLogError(m_log, "Uncaught exception %s", __PRETTY_FUNCTION__);
		MailException exc("Unable to get local emails", __FILE__, __LINE__);
		Failure(exc);
	}

	return MojErrNone;
}
MojErr ReconcileEmailsCommand::GetDeletedEmailsResponse(MojObject& response, MojErr err)
{
	try {
		MojLogDebug(m_log, "Got local deleted emails response: %s", AsJsonString(response).c_str());

		// Check database response
		ErrorToException(err);

		MojObject results;
		err = response.getRequired("results", results);
		ErrorToException(err);

		if(results.size() > 0) {
			MojLogInfo(m_log, "Got %d local deleted emails", results.size());
		}

		MojObject::ArrayIterator it;
		err = results.arrayBegin(it);
		ErrorToException(err);

		// Read email properties: _id, UID, flags
		// If you need additional properties, modify the database query
		for (; it != results.arrayEnd(); ++it) {
			MojObject& emailObj = *it;

			MojObject id;
			err = emailObj.getRequired(PopEmailAdapter::ID, id);
			ErrorToException(err);

			MojString uid;
			err = emailObj.getRequired(PopEmailAdapter::SERVER_UID, uid);
			ErrorToException(err);

			std::string uidStr(uid);
			m_localDeletedEmailUids.push_back(LocalDeletedEmailInfo(id, uidStr));

			ReconcileInfoPtr infoPtr = m_reconcileUidMap[uidStr];
			if (infoPtr.get()) {
				m_reconcileUidMap.erase(std::string(uid));
				UidMap::MessageInfo info = infoPtr->GetMessageInfo();
				int msgNum = info.GetMessageNumber();
				m_reconcileMsgNumMap.erase(msgNum);
			}
		}

		bool hasMore = DatabaseAdapter::GetNextPage(response, m_localEmailsPage);

		if(hasMore) {
			// Get next batch of emails
			MojLogDebug(m_log, "getting another batch of local deleted emails");
			GetLocalDeletedEmails();
		} else {
			MojLogDebug(m_log, "Got old emails cache");
			GetUidCache();
		}
	} catch(const std::exception& e) {
		MojLogError(m_log, "Failed to sync folder: %s", e.what());
		Failure(e);
	} catch(...) {
		MojLogError(m_log, "Uncaught exception %s", __PRETTY_FUNCTION__);
		MailException exc("Unable to get deleted emails", __FILE__, __LINE__);
		Failure(exc);
	}

	return MojErrNone;
}
Пример #14
0
void PopAccountAdapter::GetPopAccountFromPayload(MojLogger& log, const MojObject& payload, MojObject& popAccount)
{
    MojErr err = popAccount.putString(KIND, POP_ACCOUNT_KIND);
    ErrorToException(err);

    MojObject accountId;
    err = payload.getRequired(ACCOUNT_ID, accountId);
    ErrorToException(err);
    err = popAccount.put(ACCOUNT_ID, accountId);
    ErrorToException(err);

    MojObject config;
    err = payload.getRequired(CONFIG, config);
    ErrorToException(err);

    MojObject hostname;
    err = config.getRequired(HOST_NAME, hostname);
    ErrorToException(err);
    err = popAccount.put(HOST_NAME, hostname);
    ErrorToException(err);

    MojObject port;
    err = config.getRequired(PORT, port);
    ErrorToException(err);
    err = popAccount.put(PORT, port);
    ErrorToException(err);

    MojObject encryption;
    err = config.getRequired(ENCRYPTION, encryption);
    ErrorToException(err);
    err = popAccount.put(ENCRYPTION, encryption);
    ErrorToException(err);

    MojObject username;
    err = config.getRequired(USERNAME, username);
    ErrorToException(err);
    err = popAccount.put(USERNAME, username);
    ErrorToException(err);

    // Set 'deleteFromServer' flag
    bool deleteFromServer = true;
    if (!config.get(DELETE_FROM_SERVER, deleteFromServer)) {
        // default value is true if this field doesn't exist
        deleteFromServer = true;
    }
    err = popAccount.putBool(DELETE_FROM_SERVER, deleteFromServer);
    ErrorToException(err);

    // Set 'deleteOnDevice' flag
    bool deleteOnDevice = false;
    if (!config.get(DELETE_ON_DEVICE, deleteOnDevice)) {
        // defaul value is false if this field doesn't exist
        deleteOnDevice = false;
    }
    err = popAccount.putBool(DELETE_ON_DEVICE, deleteOnDevice);
    ErrorToException(err);

    // Set sync window
    MojInt64 syncWindow;
    if (!config.get(EmailAccountAdapter::SYNC_WINDOW_DAYS, syncWindow)) {
        // set default value if this field doesn't exist
        syncWindow = PopAccount::DEFAULT_SYNC_WINDOW;
    }
    err = popAccount.putInt(EmailAccountAdapter::SYNC_WINDOW_DAYS, syncWindow);
    ErrorToException(err);

    // Set sync frequency
    MojInt64 syncFreq;
    if (!config.get(SYNC_FREQUENCY_MINS, syncFreq)) {
        syncFreq = PopAccount::DEFAULT_SYNC_FREQUENCY_MINS;
    }
    err = popAccount.putInt(SYNC_FREQUENCY_MINS, syncFreq);
    ErrorToException(err);
}
Пример #15
0
MojErr MovePopEmailsCommand::GetEmailsToMoveResponse(MojObject& response, MojErr err)
{
	try {
		ErrorToException(err);

		MojLogInfo(m_log, "response to get emails to move: %s", AsJsonString(response).c_str());

		MojObject results;
		err = response.getRequired(_T("results"), results);
		ErrorToException(err);

		MojObject::ObjectVec movedEmails;
		PopClient::AccountPtr account = m_client.GetAccount();

		for (MojObject::ConstArrayIterator it = results.arrayBegin(); it != results.arrayEnd(); it++) {
			MojObject singleMovedEmail;

			MojObject id;
			err = it->getRequired(PopEmailAdapter::ID, id);
			ErrorToException(err);
			MojObject srcFolderId;
			err = it->getRequired(EmailSchema::FOLDER_ID, srcFolderId);
			ErrorToException(err);
			MojObject destFolderId;
			err = it->getRequired("destFolderId", destFolderId);
			ErrorToException(err);
			MojObject flags;
			err = it->getRequired("flags", flags);
			ErrorToException(err);

			// set to be visible
			err = flags.put("visible", true);
			ErrorToException(err);

			// setup moved email, push onto moved emails vector
			err = singleMovedEmail.put(PopEmailAdapter::ID, id);
			ErrorToException(err);
			err = singleMovedEmail.put("folderId", destFolderId);
			ErrorToException(err);
			err = singleMovedEmail.put("destFolderId", MojObject());
			ErrorToException(err);
			err = singleMovedEmail.put("flags", flags);
			ErrorToException(err);
			// add emails to be moved into 'movedEmails' list
			movedEmails.push(singleMovedEmail);

			if (account->GetInboxFolderId() == srcFolderId) {
				// add moved inbox emails inot 'm_inboxEmailsMoved' set
				MojString uid;
				err = it->getRequired(PopEmailAdapter::SERVER_UID, uid);
				ErrorToException(err);

				m_inboxEmailsMoved.insert(std::string(uid));
			}
		}

		m_client.GetDatabaseInterface().UpdateItems(m_emailsMovedSlot, movedEmails);
	} catch (const std::exception& ex) {
		m_msg->replyError(MojErrInternal, ex.what());
		Failure(ex);
	} catch (...) {
		m_msg->replyError(MojErrInternal);
		Failure(MailException("unknown exception", __FILE__, __LINE__));
	}

	return MojErrNone;
}
Пример #16
0
void PopAccountAdapter::GetPopAccount(const MojObject& in, const MojObject& transportIn, PopAccount& out)
{
    MojObject id;
    MojErr err = transportIn.getRequired(ID, id);
    ErrorToException(err);
    out.SetId(id);

    MojObject accntId;
    err = transportIn.getRequired(ACCOUNT_ID, accntId);
    ErrorToException(err);
    out.SetAccountId(accntId);

    MojString username;
    err = transportIn.getRequired(USERNAME, username);
    ErrorToException(err);
    out.SetUsername(username.data());

    MojString hostname;
    err = transportIn.getRequired(HOST_NAME, hostname);
    ErrorToException(err);
    out.SetHostName(hostname.data());

    int port;
    err = transportIn.getRequired(PORT, port);
    ErrorToException(err);
    out.SetPort(port);

    MojString encryptionStr;
    err = transportIn.getRequired(ENCRYPTION, encryptionStr);
    ErrorToException(err);
    out.SetEncryption(encryptionStr.data());

    bool initialSync;
    if (!transportIn.get(INITIAL_SYNC, initialSync)) {
        // if 'initialSynced' flag doesn't exist, it may come from an account
        // that has been created without this flag.  So set this flag to be
        // true to indicate that the account has passed the initial sync stage.
        initialSync = false;
    }
    out.SetInitialSync(initialSync);

    bool deleteFromServer;
    err = transportIn.getRequired(DELETE_FROM_SERVER, deleteFromServer);
    ErrorToException(err);
    out.SetDeleteFromServer(deleteFromServer);

    bool deleteOnDevice;
    err = transportIn.getRequired(DELETE_ON_DEVICE, deleteOnDevice);
    ErrorToException(err);
    out.SetDeleteOnDevice(deleteOnDevice);

    MojInt64 syncWindow;
    if (!transportIn.get(EmailAccountAdapter::SYNC_WINDOW_DAYS, syncWindow)) {
        // set default value if this field doesn't exist
        syncWindow = PopAccount::DEFAULT_SYNC_WINDOW;
    }
    out.SetSyncWindowDays(syncWindow);
    ErrorToException(err);

    // Set sync frequency
    MojInt64 syncFreq;
    if (!transportIn.get(SYNC_FREQUENCY_MINS, syncFreq)) {
        syncFreq = PopAccount::DEFAULT_SYNC_FREQUENCY_MINS;
    }
    out.SetSyncFrequencyMins(syncFreq);
    ErrorToException(err);

    MojObject error;
    if(transportIn.get(ERROR, error))
    {
        EmailAccount::AccountError accErr;
        MojInt64 errorCode;
        if(error.get(ERROR_CODE, errorCode))
        {
            accErr.errorCode = GetErrorCode(errorCode);
        }

        bool found = false;
        MojString errorText;
        err = error.get(ERROR_TEXT, errorText, found);
        ErrorToException(err);
        if(found)
        {
            accErr.errorText = errorText.data();
        }

        out.SetError(accErr);
    }

    MojString inboxId;
    bool exists;
    err = transportIn.get(INBOX_FOLDERID, inboxId, exists);
    ErrorToException(err);
    if (exists)
        out.SetInboxFolderId(inboxId);

    MojString outboxId;
    err = transportIn.get(OUTBOX_FOLDERID, outboxId, exists);
    ErrorToException(err);
    if (exists)
        out.SetOutboxFolderId(outboxId);

    MojString draftId;
    err = transportIn.get(DRAFTS_FOLDERID, draftId, exists);
    ErrorToException(err);
    if (exists)
        out.SetDraftsFolderId(draftId);

    MojString sentId;
    err = transportIn.get(SENT_FOLDERID, sentId, exists);
    ErrorToException(err);
    if (exists)
        out.SetSentFolderId(sentId);

    MojString trashId;
    err = transportIn.get(TRASH_FOLDERID, trashId, exists);
    ErrorToException(err);
    if (exists)
        out.SetTrashFolderId(trashId);
}
Пример #17
0
MojErr MojDbServiceHandler::findImpl(MojServiceMessage* msg, MojObject& payload, MojDbReq& req, MojDbCursor& cursor, bool doCount)
{
	MojAssert(msg);
	MojLogTrace(s_log);

	MojObject queryObj;
	MojErr err = payload.getRequired(MojDbServiceDefs::QueryKey, queryObj);
	MojErrCheck(err);
	bool doWatch = false;
	payload.get(MojDbServiceDefs::WatchKey, doWatch);

	MojDbQuery query;
	err = query.fromObject(queryObj);
	MojErrCheck(err);
	MojUInt32 limit = query.limit();
	if (limit == MojDbQuery::LimitDefault){
		query.limit(MaxQueryLimit);
	} else if (limit > MaxQueryLimit) {
		MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: limit greater than %d not allowed"), MaxQueryLimit);
	}

	if (doWatch) {
		MojRefCountedPtr<Watcher> watcher(new Watcher(msg));
		MojAllocCheck(watcher.get());
		err = m_db.find(query, cursor, watcher->m_watchSlot, req);
		MojErrCheck(err);
	} else {
		err = m_db.find(query, cursor, req);
		MojErrCheck(err);
	}

	// append results
	MojObjectVisitor& writer = msg->writer();
	err = writer.beginObject();
	MojErrCheck(err);
	err = writer.boolProp(MojServiceMessage::ReturnValueKey, true);
	MojErrCheck(err);
	err = writer.propName(MojDbServiceDefs::ResultsKey);
	MojErrCheck(err);
	err = writer.beginArray();
	MojErrCheck(err);
	err = cursor.visit(writer);
	MojErrCheck(err);
	err = writer.endArray();
	MojErrCheck(err);

	// append next page
	MojDbQuery::Page page;
	err = cursor.nextPage(page);
	MojErrCheck(err);
	if (!page.empty()) {
		MojObject pageObj;
		err = page.toObject(pageObj);
		MojErrCheck(err);
		err = writer.objectProp(MojDbServiceDefs::NextKey, pageObj);
		MojErrCheck(err);
	}

	// append count
	if (doCount) {
		MojUInt32 count = 0;
		err = cursor.count(count);
		MojErrCheck(err);
		err = writer.intProp(MojDbServiceDefs::CountKey, (MojInt64) count);
		MojErrCheck(err);
	}

	err = writer.endObject();
	MojErrCheck(err);

	if (doWatch) {
		// if this is a watched query, it cannot be part of a batch so it's safe to reply here
		err = msg->reply();
		MojErrCheck(err);
	}

	// notifications can fire any time after the cursor is closed,
	// so don't close it until after sending the reply.
	err = cursor.close();
	MojErrCheck(err);

	return MojErrNone;
}
Пример #18
0
// Copy fields from createAccount payload into com.palm.imap.account object
void ImapAccountAdapter::GetImapAccountFromPayload(const MojObject& accountObj, const MojObject& payload, MojObject& imapAccount)
{
	MojErr err = imapAccount.putString(ImapAccountAdapter::KIND, ImapAccountAdapter::SCHEMA);
	ErrorToException(err);

	MojObject accountId;
	err = payload.getRequired(ImapAccountAdapter::ACCOUNT_ID, accountId);
	ErrorToException(err);

	err = imapAccount.put(ImapAccountAdapter::ACCOUNT_ID, accountId);
	ErrorToException(err);

	MojObject config;
	err = payload.getRequired(ImapAccountAdapter::CONFIG, config);
	ErrorToException(err);

	MojString username;
	bool hasUsername = false;
	err = config.get(ImapAccountAdapter::USERNAME, username, hasUsername);
	ErrorToException(err);
	if(!hasUsername)
	{
		err = accountObj.getRequired(ImapAccountAdapter::USERNAME, username);
		ErrorToException(err);
	}
	err = imapAccount.put(ImapAccountAdapter::USERNAME, username);
	ErrorToException(err);

	MojString hostname;
	err = config.getRequired(ImapAccountAdapter::HOSTNAME, hostname);
	ErrorToException(err);

	err = imapAccount.put(ImapAccountAdapter::HOSTNAME, hostname);
	ErrorToException(err);

	int port;
	err = config.getRequired(ImapAccountAdapter::PORT, port);
	ErrorToException(err);

	err = imapAccount.put(ImapAccountAdapter::PORT, port);
	ErrorToException(err);

	MojString encryption;
	err = config.getRequired(ImapAccountAdapter::ENCRYPTION, encryption);
	ErrorToException(err);

	err = imapAccount.put(ImapAccountAdapter::ENCRYPTION, encryption);
	ErrorToException(err);

	/* Optional config parameters; fill in with defaults if not provided */

	bool hasSyncFrequency = false;
	int syncFrequencyMins = 0;
	config.get(EmailAccountAdapter::SYNC_FREQUENCY_MINS, syncFrequencyMins, hasSyncFrequency);
	ErrorToException(err);

	err = imapAccount.putInt(EmailAccountAdapter::SYNC_FREQUENCY_MINS,
			hasSyncFrequency ? syncFrequencyMins : DEFAULT_SYNC_FREQUENCY_MINS);
	ErrorToException(err);

	bool hasSyncWindow = false;
	int syncWindow = 0;
	err = config.get(EmailAccountAdapter::SYNC_WINDOW_DAYS, syncWindow, hasSyncWindow);
	ErrorToException(err);

	err = imapAccount.putInt(EmailAccountAdapter::SYNC_WINDOW_DAYS,
			hasSyncWindow ? syncWindow : DEFAULT_SYNC_WINDOW_DAYS);
	ErrorToException(err);
}
Пример #19
0
MojErr MojDb::putImpl(MojObject& obj, MojUInt32 flags, MojDbReq& req, bool checkSchema)
{
	MojLogTrace(s_log);

	MojRefCountedPtr<MojDbStorageItem> prevItem;
	MojObject id;
	if (obj.get(IdKey, id)) {
		// get previous revision if we have an id
		MojErr err = m_objDb->get(id, req.txn(), true, prevItem);
		MojErrCheck(err);
	}
	if (MojFlagGet(flags, FlagIgnoreMissing) && MojFlagGet(flags, FlagMerge)) {
		if (!prevItem.get()) {
			MojErr err = obj.putBool(MojDb::IgnoreIdKey, true);	// so that we can drop it in output
			MojErrCheck(err);
			return MojErrNone;
		}
	}

	MojDbOp op = OpCreate;
	MojObject* prevPtr = NULL;
	MojObject prev;
	if (prevItem.get()) {
		// deal with prev, if it exists
		op = OpUpdate;
		prevPtr = &prev;
		MojErr err = prevItem->toObject(prev, m_kindEngine);
		MojErrCheck(err);

		if (MojFlagGet(flags, FlagMerge)) {
			// do merge
			MojObject merged;
			err = mergeInto(merged, obj, prev);
			MojErrCheck(err);
			obj = merged;
		} else if (!MojFlagGet(flags, FlagForce)) {
			// if the force flag is not set, throw error if we are updating
			// an existing, non-deleted object and no rev was specified
			MojInt64 rev;
			if (obj.get(RevKey, rev) == false) {
				bool deleted = false;
				if (!prev.get(DelKey, deleted) || !deleted)
					MojErrThrow(MojErrDbRevNotSpecified);
			}
		}
	}

	// if the new object has a rev and it doesn't match the old rev, don't do the update
	MojInt64 newRev;
	if (prevPtr != NULL && obj.get(RevKey, newRev)) {
		MojInt64 oldRev;
		MojErr err = prevPtr->getRequired(RevKey, oldRev);
		MojErrCheck(err);
		if (!MojFlagGet(flags, FlagForce) && newRev != oldRev)
			MojErrThrowMsg(MojErrDbRevisionMismatch, _T("db: revision mismatch - expected %lld, got %lld"), oldRev, newRev);
	}

	// save it
	MojErr err = putObj(id, obj, prevPtr, prevItem.get(), req, op, checkSchema);
	MojErrCheck(err);

	if (prevItem.get()) {
		err = prevItem->close();
		MojErrCheck(err);
	}
	return MojErrNone;
}
MojErr ActivityConfigurator::ProcessConfig(const string& filePath, MojObject& params)
{
	MojLogTrace(m_log);

	const std::string& creator = ParentId(filePath);

	if (creator.empty()) {
		MojLogError(m_log, "Service id for activity '%s' is empty - needs to be in an appropriate subdirectory or given as part of the service call", filePath.c_str());
		return MojErrInvalidArg;
	}

	if (m_firstUseOnly) {
		bool firstUseSafe;
		if (!params.get(FIRST_USE_SAFE, firstUseSafe) || !firstUseSafe) {
			MojLogDebug(m_log, "Running before first use but activity %s not marked as safe for configuration at this time", filePath.c_str());
			return MojErrInProgress;
		}
	}

	MojLogDebug(m_log, "ActivityConfigurator creator for %s is %s\n", filePath.c_str(), creator.c_str());

	MojObject activity;
	MojErr err;
	err = params.getRequired(ACTIVITY, activity);
	MojErrCheck(err);

	ConfigType confType;

	if (m_confType == ConfigUnknown) {
		if (StartsWith(filePath, APP_DIR)) {
			confType = ConfigApplication;
		} else {
			if (!StartsWith(filePath, SERVICE_DIR)) {
				//Fix for DFISH-14510 turn down logging here
				//MojLogWarning(m_log, "Deprecated usage: %s not in application or service subdirectory as required - assumed to be service", filePath.c_str());
			}
			confType = ConfigService;
		}
	} else {
		confType = m_confType;
	}

	MojObject creatorObj;
	switch (confType) {
	case ConfigApplication:
		err = creatorObj.putString(APPLICATION_ID, creator.c_str());
		break;
	case ConfigService:
		err = creatorObj.putString(SERVICE_ID, creator.c_str());
		break;
	case ConfigUnknown:
		// impossible case
		assert(false);
		break;
	}

	MojErrCheck(err);

	err = activity.put(CREATOR, creatorObj);
	MojErrCheck(err);
	err = params.put(ACTIVITY, activity);
	MojErrCheck(err);

	// strip configurator-specific keys
	// so that the schema on activity manager isn't violated
	RemoveKey(params, FIRST_USE_SAFE);

	return m_busClient.CreateRequest()->send(CreateCallback(filePath)->m_slot, ServiceName(), ACTIVITYMGR_CREATE_METHOD, params);
}
//TODO: when the connection is lost (no internet), complete/cancel the activity and exit the service
MojErr ConnectionState::ConnectionStateHandler::connectionManagerResult(MojObject& result, MojErr err)
{
	// log the parameters
	IMServiceHandler::logMojObjectJsonString(_T("ConnectionStateHandler::connectionManagerResult: %s"), result);

	if (err == MojErrNone && result.contains("$activity"))
	{
		MojObject activity, requirements, internetRequirements;
		// The connectionmanager status is under $activity.requirements.internet
		err = result.getRequired("$activity", activity);
		if (err == MojErrNone)
		{
			err = activity.getRequired("requirements", requirements);
			if (err == MojErrNone)
			{
				err = requirements.getRequired("internet", internetRequirements);
			}
		}

		if (err == MojErrNone)
		{
			m_receivedResponse = true;
			bool prevInetConnected = m_connState->m_inetConnected;
			internetRequirements.get("isInternetConnectionAvailable", m_connState->m_inetConnected);

			bool prevWifiConnected = m_connState->m_wifiConnected;
			bool found = false;
			MojObject wifiObj;
			err = internetRequirements.getRequired("wifi", wifiObj);
			MojString wifiState;
			err = wifiObj.getRequired("state", wifiState);
			m_connState->m_wifiConnected = (err == MojErrNone && wifiState.compare("connected") == 0);
			// If the connection was lost, keep the old ipAddress so it can be used to
			// notify accounts that were using it
			if (m_connState->m_wifiConnected == true)
			{
				err = wifiObj.get("ipAddress", m_connState->m_wifiIpAddress, found);
				if (err != MojErrNone || found == false)
				{
					// It may claim to be connected, but there's no interface IP address
					MojLogError(IMServiceApp::s_log, _T("Marking WiFi as disconnected because ipAddress is missing"));
					m_connState->m_wifiConnected = false;
				}
				MojLogInfo(IMServiceApp::s_log, _T("ConnectionStateHandler::connectionManagerResult found=%i, wifi ipAddress=%s"), found, m_connState->m_wifiIpAddress.data());
			}

			bool prevWanConnected = m_connState->m_wanConnected;

			MojObject wanObj;
			err = internetRequirements.getRequired("wan", wanObj);
			MojErrCheck(err);

			MojString wanState;
			err = wanObj.getRequired("state", wanState);
			MojErrCheck(err);

			m_connState->m_wanConnected = (err == MojErrNone && wanState.compare("connected") == 0);
			// If the connection was lost, keep the old ipAddress so it can be used to
			// notify accounts that were using it
			if (m_connState->m_wanConnected == true)
			{
				err = wanObj.get("ipAddress", m_connState->m_wanIpAddress, found);
				if (err != MojErrNone || found == false)
				{
					// It may claim to be connected, but there's no interface IP address
					MojLogError(IMServiceApp::s_log, _T("Marking WAN as disconnected because ipAddress is missing"));
					m_connState->m_wanConnected = false;
				}
				MojLogInfo(IMServiceApp::s_log, _T("ConnectionStateHandler::connectionManagerResult found=%i, wan ipAddress=%s"), found, m_connState->m_wanIpAddress.data());
			}

			// If the loginState machine setup a listener, then post the change
			if (m_loginState != NULL)
			{
				if (prevInetConnected != m_connState->m_inetConnected ||
					prevWifiConnected != m_connState->m_wifiConnected ||
					prevWanConnected != m_connState->m_wanConnected)
				{
					MojLogInfo(IMServiceApp::s_log, _T("ConnectionStateHandler::connectionManagerResult - connection changed - scheduling activity."));
					ConnectionState::ConnectionChangedScheduler *changeScheduler = new ConnectionState::ConnectionChangedScheduler(m_service);
					changeScheduler->scheduleActivity();
				}
				else {
					MojLogInfo(IMServiceApp::s_log, _T("ConnectionStateHandler::connectionManagerResult - no change from previous state."));
				}
			}
		}
	}
	else {
		MojLogInfo(IMServiceApp::s_log, _T("ConnectionStateHandler::connectionManagerResult no activity object - ignoring. err = %d"), err);
	}
	return MojErrNone;
}