Changeset - de8114d2da06
[Not reviewed]
0 3 0
Jan Kaluza - 10 years ago 2016-02-09 08:01:04
jkaluza@redhat.com
Libpurple: Do not change the nickname when joining the room when it is the same as the one used by the user
3 files changed with 6 insertions and 6 deletions:
0 comments (0 inline, 0 general)
backends/libpurple/main.cpp
Show inline comments
 
@@ -617,200 +617,200 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
 
					if (!group) {
 
						group = purple_group_new_wrapped(groups.c_str());
 
					}
 
					purple_blist_add_contact_wrapped(purple_buddy_get_contact_wrapped(buddy), group ,NULL);
 
				}
 
				else {
 
					PurpleBuddy *buddy = purple_buddy_new_wrapped(account, buddyName.c_str(), alias.c_str());
 

	
 
					// Add newly created buddy to legacy network roster.
 
					PurpleGroup *group = purple_find_group_wrapped(groups.c_str());
 
					if (!group) {
 
						group = purple_group_new_wrapped(groups.c_str());
 
					}
 
					purple_blist_add_buddy_wrapped(buddy, NULL, group ,NULL);
 
					purple_account_add_buddy_wrapped(account, buddy);
 
					LOG4CXX_INFO(logger, "Adding new buddy " << buddyName.c_str() << " to legacy network roster");
 
				}
 
			}
 
		}
 

	
 
		void handleBuddyBlockToggled(const std::string &user, const std::string &buddyName, bool blocked) {
 
			if (CONFIG_BOOL(config, "service.enable_privacy_lists")) {
 
				PurpleAccount *account = m_sessions[user];
 
				if (account) {
 
					if (blocked) {
 
						purple_privacy_deny_wrapped(account, buddyName.c_str(), FALSE, FALSE);
 
					}
 
					else {
 
						purple_privacy_allow_wrapped(account, buddyName.c_str(), FALSE, FALSE);
 
					}
 
				}
 
			}
 
		}
 

	
 
		void handleTypingRequest(const std::string &user, const std::string &buddyName) {
 
			PurpleAccount *account = m_sessions[user];
 
			if (account) {
 
				LOG4CXX_INFO(logger, user << ": sending typing notify to " << buddyName);
 
				serv_send_typing_wrapped(purple_account_get_connection_wrapped(account), buddyName.c_str(), PURPLE_TYPING);
 
			}
 
		}
 

	
 
		void handleTypedRequest(const std::string &user, const std::string &buddyName) {
 
			PurpleAccount *account = m_sessions[user];
 
			if (account) {
 
				serv_send_typing_wrapped(purple_account_get_connection_wrapped(account), buddyName.c_str(), PURPLE_TYPED);
 
			}
 
		}
 

	
 
		void handleStoppedTypingRequest(const std::string &user, const std::string &buddyName) {
 
			PurpleAccount *account = m_sessions[user];
 
			if (account) {
 
				serv_send_typing_wrapped(purple_account_get_connection_wrapped(account), buddyName.c_str(), PURPLE_NOT_TYPING);
 
				PurpleConversation *conv = purple_find_conversation_with_account_wrapped(PURPLE_CONV_TYPE_CHAT, buddyName.c_str(), account);
 
				if (!conv) {
 
					conv = purple_find_conversation_with_account_wrapped(PURPLE_CONV_TYPE_IM, buddyName.c_str(), account);
 
				}
 
				if (conv) {
 
					purple_conversation_set_data_wrapped(conv, "unseen_count", 0);
 
					purple_conversation_update_wrapped(conv, PURPLE_CONV_UPDATE_UNSEEN);
 
				}
 
			}
 
		}
 

	
 
		void handleAttentionRequest(const std::string &user, const std::string &buddyName, const std::string &message) {
 
			PurpleAccount *account = m_sessions[user];
 
			if (account) {
 
				purple_prpl_send_attention_wrapped(purple_account_get_connection_wrapped(account), buddyName.c_str(), 0);
 
			}
 
		}
 

	
 
		void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &pasword) {
 
			PurpleAccount *account = m_sessions[user];
 
			if (!account) {
 
				return;
 
			}
 

	
 
			PurpleConnection *gc = purple_account_get_connection_wrapped(account);
 
			GHashTable *comps = NULL;
 

	
 
			// Check if the PurpleChat is not stored in buddy list
 
			PurpleChat *chat = purple_blist_find_chat_wrapped(account, room.c_str());
 
			if (chat) {
 
				comps = purple_chat_get_components_wrapped(chat);
 
			}
 
			else if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL) {
 
				if (CONFIG_STRING(config, "service.protocol") == "prpl-jabber") {
 
					comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, (room + "/" + nickname).c_str());
 
				} else {
 
					comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, room.c_str());
 
				}
 
			}
 

	
 
			if (CONFIG_STRING(config, "service.protocol") != "prpl-jabber") {
 
				np->handleParticipantChanged(np->m_accounts[account], nickname, room, 0, pbnetwork::STATUS_ONLINE);
 
				const char *disp;
 
				if ((disp = purple_connection_get_display_name(account->gc))) {
 
				if ((disp = purple_connection_get_display_name(account->gc)) == NULL) {
 
					disp = purple_account_get_username(account);
 
				}
 

	
 
				if (nickname != disp) {
 
					handleRoomNicknameChanged(np->m_accounts[account], room, disp);
 
					np->handleParticipantChanged(np->m_accounts[account], nickname, room, 0, pbnetwork::STATUS_ONLINE, "", disp);
 
				}
 
				else {
 
					handleRoomNicknameChanged(np->m_accounts[account], room, purple_account_get_username(account));
 
					np->handleParticipantChanged(np->m_accounts[account], nickname, room, 0, pbnetwork::STATUS_ONLINE, "", purple_account_get_username(account));
 
				}
 
			}
 

	
 
			LOG4CXX_INFO(logger, user << ": Joining the room " << room);
 
			if (comps) {
 
				serv_join_chat_wrapped(gc, comps);
 
				g_hash_table_destroy(comps);
 
			}
 
		}
 

	
 
		void handleLeaveRoomRequest(const std::string &user, const std::string &room) {
 
			PurpleAccount *account = m_sessions[user];
 
			if (!account) {
 
				return;
 
			}
 

	
 
			PurpleConversation *conv = purple_find_conversation_with_account_wrapped(PURPLE_CONV_TYPE_CHAT, room.c_str(), account);
 
			purple_conversation_destroy_wrapped(conv);
 
		}
 

	
 
		void handleFTStartRequest(const std::string &user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID) {
 
			PurpleXfer *xfer = m_unhandledXfers[user + fileName + buddyName];
 
			if (xfer) {
 
				m_unhandledXfers.erase(user + fileName + buddyName);
 
				FTData *ftData = (FTData *) xfer->ui_data;
 
				
 
				ftData->id = ftID;
 
				m_xfers[ftID] = xfer;
 
				purple_xfer_request_accepted_wrapped(xfer, fileName.c_str());
 
				purple_xfer_ui_ready_wrapped(xfer);
 
			}
 
		}
 

	
 
		void handleFTFinishRequest(const std::string &user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID) {
 
			PurpleXfer *xfer = m_unhandledXfers[user + fileName + buddyName];
 
			if (xfer) {
 
				m_unhandledXfers.erase(user + fileName + buddyName);
 
				purple_xfer_request_denied_wrapped(xfer);
 
			}
 
		}
 

	
 
		void handleFTPauseRequest(unsigned long ftID) {
 
			PurpleXfer *xfer = m_xfers[ftID];
 
			if (!xfer)
 
				return;
 
			FTData *ftData = (FTData *) xfer->ui_data;
 
			ftData->paused = true;
 
		}
 

	
 
		void handleFTContinueRequest(unsigned long ftID) {
 
			PurpleXfer *xfer = m_xfers[ftID];
 
			if (!xfer)
 
				return;
 
			FTData *ftData = (FTData *) xfer->ui_data;
 
			ftData->paused = false;
 
			purple_xfer_ui_ready_wrapped(xfer);
 
		}
 

	
 
		void sendData(const std::string &string) {
 
#ifdef WIN32
 
			::send(main_socket, string.c_str(), string.size(), 0);
 
#else
 
			write(main_socket, string.c_str(), string.size());
 
#endif
 
			if (writeInput == 0)
 
				writeInput = purple_input_add_wrapped(main_socket, PURPLE_INPUT_WRITE, &transportDataReceived, NULL);
 
		}
 

	
 
		void readyForData() {
 
			if (m_waitingXfers.empty())
 
				return;
 
			std::vector<PurpleXfer *> tmp;
 
			tmp.swap(m_waitingXfers);
 

	
 
			for (std::vector<PurpleXfer *>::const_iterator it = tmp.begin(); it != tmp.end(); it++) {
 
				FTData *ftData = (FTData *) (*it)->ui_data;
 
				if (ftData->timer == 0) {
 
					ftData->timer = purple_timeout_add_wrapped(1, ft_ui_ready, *it);
 
				}
 
// 				purple_xfer_ui_ready_wrapped(xfer);
 
			}
 
		}
 

	
 
		std::map<std::string, PurpleAccount *> m_sessions;
 
		std::map<PurpleAccount *, std::string> m_accounts;
 
		std::map<std::string, unsigned int> m_vcards;
 
		std::map<std::string, authRequest *> m_authRequests;
 
		std::map<unsigned long, PurpleXfer *> m_xfers;
 
		std::map<std::string, PurpleXfer *> m_unhandledXfers;
 
		std::vector<PurpleXfer *> m_waitingXfers;
 
};
 

	
 
static bool getStatus(PurpleBuddy *m_buddy, pbnetwork::StatusType &status, std::string &statusMessage) {
 
	PurplePresence *pres = purple_buddy_get_presence_wrapped(m_buddy);
 
	if (pres == NULL)
 
		return false;
 
	PurpleStatus *stat = purple_presence_get_active_status_wrapped(pres);
libtransport/Conversation.cpp
Show inline comments
 
@@ -220,181 +220,182 @@ void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, con
 
}
 

	
 
std::string Conversation::getParticipants() {
 
	std::string ret;
 
	for (std::map<std::string, Participant>::iterator it = m_participants.begin(); it != m_participants.end(); it++) {
 
		ret += (*it).second.presence->getFrom().getResource() + ", ";
 
	}
 
	return ret;
 
}
 

	
 
void Conversation::sendParticipants(const Swift::JID &to) {
 
	for (std::map<std::string, Participant>::iterator it = m_participants.begin(); it != m_participants.end(); it++) {
 
		(*it).second.presence->setTo(to);
 
		m_conversationManager->getComponent()->getFrontend()->sendPresence((*it).second.presence);
 
	}
 
}
 

	
 
void Conversation::sendCachedMessages(const Swift::JID &to) {
 
	for (std::list<boost::shared_ptr<Swift::Message> >::const_iterator it = m_cachedMessages.begin(); it != m_cachedMessages.end(); it++) {
 
		if (to.isValid()) {
 
			(*it)->setTo(to);
 
		}
 
		else {
 
			(*it)->setTo(m_jid.toBare());
 
		}
 
		m_conversationManager->getComponent()->getFrontend()->sendMessage(*it);
 
	}
 

	
 
	if (m_subject) {
 
		if (to.isValid()) {
 
			m_subject->setTo(to);
 
		}
 
		else {
 
			m_subject->setTo(m_jid.toBare());
 
		}
 
		m_conversationManager->getComponent()->getFrontend()->sendMessage(m_subject);
 
	}
 

	
 
	m_cachedMessages.clear();
 
}
 

	
 
Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname, const std::string &iconhash) {
 
	std::string nickname = nick;
 
	Swift::Presence::ref presence = Swift::Presence::create();
 
	std::string legacyName = m_legacyName;
 
	if (m_muc) {
 
		if (!m_mucEscaping && legacyName.find_last_of("@") != std::string::npos) {
 
			legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK
 
		}
 
		legacyName = Swift::JID::getEscapedNode(legacyName);
 
	}
 
	presence->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), nickname));
 
	presence->setType(Swift::Presence::Available);
 

	
 
	if (!statusMessage.empty())
 
		presence->setStatus(statusMessage);
 

	
 
	Swift::StatusShow s((Swift::StatusShow::Type) status);
 

	
 
	if (s.getType() == Swift::StatusShow::None) {
 
		presence->setType(Swift::Presence::Unavailable);
 
	}
 

	
 
	presence->setShow(s.getType());
 

	
 
	Swift::MUCUserPayload *p = new Swift::MUCUserPayload ();
 
	if (m_nickname == nickname) {
 
		if (flag & PARTICIPANT_FLAG_CONFLICT) {
 
			delete p;
 
			presence->setType(Swift::Presence::Error);
 
			presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::MUCPayload()));
 
			presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::ErrorPayload(Swift::ErrorPayload::Conflict)));
 
			return presence;
 
		}
 
		else if (flag & PARTICIPANT_FLAG_NOT_AUTHORIZED) {
 
			delete p;
 
			presence->setType(Swift::Presence::Error);
 
			presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::MUCPayload()));
 
			presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::ErrorPayload(Swift::ErrorPayload::NotAuthorized, Swift::ErrorPayload::Auth, statusMessage)));
 
			return presence;
 
		}
 
		else if (flag & PARTICIPANT_FLAG_ROOM_NOT_FOUD) {
 
			delete p;
 
			presence->setType(Swift::Presence::Error);
 
			presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::MUCPayload()));
 
			presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::ErrorPayload(Swift::ErrorPayload::ItemNotFound, Swift::ErrorPayload::Cancel, statusMessage)));
 
			return presence;
 
		}
 
		else {
 
			Swift::MUCUserPayload::StatusCode c;
 
			c.code = 110;
 
			p->addStatusCode(c);
 
			if (m_nicknameChanged) {
 
				Swift::MUCUserPayload::StatusCode c;
 
				c.code = 210;
 
				p->addStatusCode(c);
 
				m_nicknameChanged = false;
 
			}
 
			m_sentInitialPresence = true;
 
		}
 
	}
 

	
 

	
 
	Swift::MUCItem item;
 
	
 
	item.affiliation = Swift::MUCOccupant::Member;
 
	item.role = Swift::MUCOccupant::Participant;
 

	
 
	if (flag & PARTICIPANT_FLAG_MODERATOR) {
 
		item.affiliation = Swift::MUCOccupant::Admin;
 
		item.role = Swift::MUCOccupant::Moderator;
 
	}
 

	
 
	if (!newname.empty()) {
 
		item.nick = newname;
 
		Swift::MUCUserPayload::StatusCode c;
 
		c.code = 303;
 
		p->addStatusCode(c);
 
		presence->setType(Swift::Presence::Unavailable);
 
	}
 

	
 
	if (!iconhash.empty()) {
 
		presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::VCardUpdate (iconhash)));
 
	}
 
	
 
	p->addItem(item);
 
	presence->addPayload(boost::shared_ptr<Swift::Payload>(p));
 
	return presence;
 
}
 

	
 

	
 
void Conversation::setNickname(const std::string &nickname) {
 
	if (!nickname.empty() && m_nickname != nickname) {
 
		m_nicknameChanged = true;
 
	}
 
	m_nickname = nickname;
 
}
 

	
 
void Conversation::handleRawPresence(Swift::Presence::ref presence) {
 
	// TODO: Detect nickname change.
 
	m_conversationManager->getComponent()->getFrontend()->sendPresence(presence);
 
	m_participants[presence->getFrom().getResource()].presence = presence;
 
}
 

	
 
void Conversation::removeJID(const Swift::JID &jid) {
 
	m_jids.remove(jid);
 
}
 

	
 
void Conversation::handleParticipantChanged(const std::string &nick, Conversation::ParticipantFlag flag, int status, const std::string &statusMessage, const std::string &newname, const std::string &iconhash, const std::string &alias) {
 
	Swift::Presence::ref presence = generatePresence(alias.empty() ? nick : alias, flag, status, statusMessage, newname, iconhash);
 

	
 
	if (presence->getType() == Swift::Presence::Unavailable) {
 
		m_participants.erase(nick);
 
	}
 
	else {
 
		m_participants[nick].presence = presence;
 
		m_participants[nick].alias = alias;
 
	}
 

	
 

	
 
	BOOST_FOREACH(const Swift::JID &jid, m_jids) {
 
		presence->setTo(jid);
 
		m_conversationManager->getComponent()->getFrontend()->sendPresence(presence);
 
	}
 
	if (!newname.empty()) {
 
		handleParticipantChanged(newname, flag, status, statusMessage, "", iconhash);
 
	}
 

	
 
	if (m_sentInitialPresence && m_subject) {
 
		m_conversationManager->getComponent()->getFrontend()->sendMessage(m_subject);
 
		m_subject.reset();
 
	}
 

	
 
	// We send error presences only to inform user that he is disconnected
 
	// from the room. This code must be extended in case we start sending error
 
	// presences in other situations.
 
	if (presence->getType() == Swift::Presence::Error) {
 
		m_conversationManager->getUser()->leaveRoom(m_legacyName);
 
	}
 
}
 

	
 
}
tests/libtransport/localbuddy.cpp
Show inline comments
 
@@ -46,105 +46,104 @@ class LocalBuddyTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
 
		CPPUNIT_ASSERT(user);
 

	
 
		std::vector<std::string> grp;
 
		grp.push_back("group");
 

	
 
		// with BUDDY_JID_ESCAPING it escapes /
 
		LocalBuddy *buddy = new LocalBuddy(user->getRosterManager(), -1, "msn/something", "Buddy 1", grp, BUDDY_JID_ESCAPING);
 
		CPPUNIT_ASSERT(buddy->isValid());
 
		CPPUNIT_ASSERT_EQUAL(std::string("msn\\2fsomething@localhost/bot"), buddy->getJID().toString());
 
		delete buddy;
 

	
 
		// without BUDDY_JID_ESCAPING it shoudl fail
 
		buddy = new LocalBuddy(user->getRosterManager(), -1, "msn/something", "Buddy 1", grp);
 
		CPPUNIT_ASSERT(!buddy->isValid());
 
		delete buddy;
 

	
 
		buddy = new LocalBuddy(user->getRosterManager(), -1, "\xd7\x92\xd7\x9c\xd7\x99\xd7\x9d@nimbuzz.com", "Buddy 1", grp);
 
		CPPUNIT_ASSERT(!buddy->isValid());
 
		delete buddy;
 
	}
 

	
 
	void JIDToLegacyName() {
 
		CPPUNIT_ASSERT_EQUAL(std::string("hanzz@test"), Buddy::JIDToLegacyName("hanzz\\40test@localhost/bot"));
 
		CPPUNIT_ASSERT_EQUAL(std::string("hanzz@test"), Buddy::JIDToLegacyName("hanzz%test@localhost/bot"));
 
	}
 

	
 
	void getSafeName() {
 
		User *user = userManager->getUser("user@localhost");
 
		CPPUNIT_ASSERT(user);
 

	
 
		std::vector<std::string> grp;
 
		grp.push_back("group1");
 
		LocalBuddy *buddy = new LocalBuddy(user->getRosterManager(), -1, "buddy1@test", "Buddy 1", grp, BUDDY_JID_ESCAPING);
 

	
 
		CPPUNIT_ASSERT_EQUAL(std::string("buddy1\\40test"), buddy->getSafeName());
 

	
 
		buddy->setFlags(BUDDY_NO_FLAG);
 
		CPPUNIT_ASSERT_EQUAL(std::string("buddy1%test"), buddy->getSafeName());
 
	}
 

	
 
	void buddyFlagsFromJID() {
 
		CPPUNIT_ASSERT_EQUAL(BUDDY_JID_ESCAPING, Buddy::buddyFlagsFromJID("hanzz\\40test@localhost/bot"));
 
		CPPUNIT_ASSERT_EQUAL(BUDDY_NO_FLAG, Buddy::buddyFlagsFromJID("hanzz%test@localhost/bot"));
 
	}
 

	
 
	void sendPresence() {
 
		User *user = userManager->getUser("user@localhost");
 
		CPPUNIT_ASSERT(user);
 

	
 
		std::vector<std::string> grp;
 
		grp.push_back("group1");
 
		LocalBuddy *buddy = new LocalBuddy(user->getRosterManager(), -1, "buddy1", "Buddy 1", grp, BUDDY_JID_ESCAPING);
 
		buddy->setStatus(Swift::StatusShow(Swift::StatusShow::Away), "status1");
 
		user->getRosterManager()->setBuddy(buddy);
 
		received.clear();
 

	
 
		buddy->sendPresence();
 
		CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 
		CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[0])));
 
		CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast<Swift::Presence *>(getStanza(received[0]))->getShow());
 
		CPPUNIT_ASSERT_EQUAL(std::string("status1"), dynamic_cast<Swift::Presence *>(getStanza(received[0]))->getStatus());
 
	}
 

	
 
	void setAlias() {
 
		User *user = userManager->getUser("user@localhost");
 
		CPPUNIT_ASSERT(user);
 

	
 
		std::vector<std::string> grp;
 
		grp.push_back("group1");
 
		LocalBuddy *buddy = new LocalBuddy(user->getRosterManager(), -1, "buddy1", "Buddy 1", grp, BUDDY_JID_ESCAPING);
 
		buddy->setStatus(Swift::StatusShow(Swift::StatusShow::Away), "status1");
 
		user->getRosterManager()->setBuddy(buddy);
 
		received.clear();
 

	
 
		buddy->setAlias("Buddy 2");
 
		CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 
		Swift::RosterPayload::ref payload1 = getStanza(received[0])->getPayload<Swift::RosterPayload>();
 
		CPPUNIT_ASSERT(payload1);
 
		CPPUNIT_ASSERT_EQUAL(1, (int) payload1->getItems().size());
 
		Swift::RosterItemPayload item = payload1->getItems()[0];
 
		CPPUNIT_ASSERT_EQUAL(std::string("buddy1"), Buddy::JIDToLegacyName(item.getJID()));
 
		CPPUNIT_ASSERT_EQUAL(std::string("Buddy 2"), item.getName());
 
	}
 

	
 
	void sendPresenceTypeNone() {
 
		User *user = userManager->getUser("user@localhost");
 
		CPPUNIT_ASSERT(user);
 

	
 
		std::vector<std::string> grp;
 
		grp.push_back("group1");
 
		LocalBuddy *buddy = new LocalBuddy(user->getRosterManager(), -1, "buddy1", "Buddy 1", grp, BUDDY_JID_ESCAPING);
 
		buddy->setStatus(Swift::StatusShow(Swift::StatusShow::Away), "");
 
		user->getRosterManager()->setBuddy(buddy);
 
		received.clear();
 

	
 
		buddy->setStatus(Swift::StatusShow(Swift::StatusShow::None), "");
 
		dumpReceived();
 
		CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 
		CPPUNIT_ASSERT(dynamic_cast<Swift::Presence *>(getStanza(received[0])));
 
		CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::None, dynamic_cast<Swift::Presence *>(getStanza(received[0]))->getShow());
 
	}
 

	
 
};
 

	
 
CPPUNIT_TEST_SUITE_REGISTRATION (LocalBuddyTest);
0 comments (0 inline, 0 general)