////////////////////////////////////////////////// // Blabber [JRoster.cpp] ////////////////////////////////////////////////// #include #include #include "JabberSpeak.h" #include "JRoster.h" #include "Messages.h" #include "MessageRepeater.h" #include "ui/ModalAlertFactory.h" JRoster *JRoster::_instance = NULL; JRoster *JRoster::Instance() { if (_instance == NULL) { _instance = new JRoster(); } return _instance; } JRoster::~JRoster() { _instance = NULL; // destroy semaphore delete_sem(_roster_lock); } void JRoster::AddNewUser(const gloox::JID& new_user, std::string friendlyName) { _roster->push_back(new UserID(new_user)); // communicate the new user to the server gloox::Client* client = JabberSpeak::Instance()->GlooxClient(); gloox::StringList groups; client->rosterManager()->add(new_user, friendlyName, groups); client->rosterManager()->synchronize(); // refresh all roster views RefreshRoster(); } void JRoster::RemoveUser(const gloox::JID& removed_user) { for (RosterIter i = _roster->begin(); i != _roster->end(); ++i) { if ((*i)->JID() == removed_user) { // for transports if ((*i)->UserType() == UserID::TRANSPORT) { Agent *agent = AgentList::Instance()->GetAgentByID((*i)->TransportID()); if (agent) { agent->SetRegisteredFlag(false); } } // goodbye memory delete (*i); _roster->erase(i); break; } } } void JRoster::RemoveAllUsers() { // BUGBUG need more elegant way of deleting all users (check STL guide) while(_roster->begin() != _roster->end()) { RosterIter i = _roster->begin(); UserID *user = *i; _roster->erase(i); delete user; } } UserID *JRoster::FindUser(search_method search_type, string name) { if (search_type == JRoster::HANDLE) { for (RosterIter i = _roster->begin(); i != _roster->end(); ++i) { if (!strcasecmp(name.c_str(), (*i)->JabberHandle().c_str())) { return (*i); } } } if (search_type == JRoster::COMPLETE_HANDLE) { for (RosterIter i = _roster->begin(); i != _roster->end(); ++i) { if (!strcasecmp(name.c_str(), (*i)->JabberCompleteHandle().c_str())) { return (*i); } } } if (search_type == JRoster::TRANSPORT_ID) { for (RosterIter i = _roster->begin(); i != _roster->end(); ++i) { if (!strcasecmp(name.c_str(), (*i)->TransportID().c_str())) { return (*i); } } } return NULL; } UserID *JRoster::FindUser(const gloox::JID& comparing_user) { return FindUser(JRoster::HANDLE, comparing_user.bare()); } UserID::online_status JRoster::UserStatus(string username) { UserID *user = FindUser(COMPLETE_HANDLE, username); if (user != NULL) { return user->OnlineStatus(); } return UserID::UNKNOWN; } JRoster::ConstRosterIter JRoster::BeginIterator() { return _roster->begin(); } JRoster::ConstRosterIter JRoster::EndIterator() { return _roster->end(); } void JRoster::RefreshRoster() { // update everyone to the change MessageRepeater::Instance()->PostMessage(BLAB_UPDATE_ROSTER); MessageRepeater::Instance()->PostMessage(TRANSPORT_UPDATE); } void JRoster::Lock() { acquire_sem(_roster_lock); } void JRoster::Unlock() { release_sem(_roster_lock); } void JRoster::handleItemAdded(const gloox::JID&) { printf("%s\n", __PRETTY_FUNCTION__); } void JRoster::handleItemSubscribed(const gloox::JID&) { printf("%s\n", __PRETTY_FUNCTION__); #if 0 user->SetOnlineStatus(UserID::ONLINE); if (entity->Child("status")) { sprintf(buffer, "[%s]\n\n%s", asker, entity->Child("status")->Data()); } else { sprintf(buffer, "Your subscription request was accepted by %s!", asker); } ModalAlertFactory::Alert(buffer, "Hooray!"); #endif } void JRoster::handleItemRemoved(const gloox::JID&) { printf("%s\n", __PRETTY_FUNCTION__); } void JRoster::handleItemUpdated(const gloox::JID& jid) { gloox::Client* client = JabberSpeak::Instance()->GlooxClient(); gloox::RosterItem* item = client->rosterManager()->getRosterItem(jid); UserID* roster_user = FindUser(JRoster::HANDLE, jid.full()); if (roster_user) { roster_user->SetSubscriptionStatus(item->subscription()); } else { printf("%s(%s) user not found\n", __PRETTY_FUNCTION__, jid.full().c_str()); } } void JRoster::handleItemUnsubscribed(const gloox::JID&) { printf("%s\n", __PRETTY_FUNCTION__); #if 0 user->SetOnlineStatus(UserID::UNKNOWN); #endif } void JRoster::handleRoster(const gloox::Roster& roster) { Lock(); for (auto item: roster) { UserID user(item.first); user.SetSubscriptionStatus(item.second->subscription()); // obtain a handle to the user (is there a new one?) UserID *roster_user; if (user.IsUser()) { roster_user = FindUser(JRoster::HANDLE, user.JabberHandle()); } else if (user.UserType() == UserID::TRANSPORT) { roster_user = FindUser(JRoster::TRANSPORT_ID, user.TransportID()); } else { continue; } // if we have duplicates, settle disputes if (roster_user) { #if 0 // process if it's a removal if (entity->Child(i)->Attribute("subscription") && !strcasecmp(entity->Child(i)->Attribute("subscription"), "remove")) { // remove from the list RemoveUser(roster_user); continue; } #endif // update the new roster item *roster_user = user; } else { // create the user roster_user = new UserID(item.first); *roster_user = user; // add to the list _roster->push_back(roster_user); } } Unlock(); // update all RosterViews RefreshRoster(); } void JRoster::handleRosterPresence(const gloox::RosterItem& item, const string& resource __attribute__((unused)), gloox::Presence::PresenceType presenceType, const string& message) { int num_matches = 0; const gloox::JID& jid = item.jidJID(); Lock(); for (JRoster::ConstRosterIter i = BeginIterator(); i != EndIterator(); ++i) { UserID *user = NULL; if ((*i)->IsUser() && !strcasecmp(UserID(jid.full()).JabberHandle().c_str(), (*i)->JabberHandle().c_str())) { // found another match ++num_matches; user = *i; _ProcessUserPresence(user, presenceType, message); } else if ((*i)->UserType() == UserID::TRANSPORT && !strcasecmp(UserID(jid.full()).TransportID().c_str(), (*i)->TransportID().c_str())) { // found another match ++num_matches; user = *i; _ProcessUserPresence(user, presenceType, message); } } if (num_matches == 0) { #if 0 UserID user(jid.full()); ProcessUserPresence(&user, presence); #endif puts("user not found"); } Unlock(); // update all RosterViews RefreshRoster(); } void JRoster::handleSelfPresence(const gloox::RosterItem&, const string& resource, gloox::Presence::PresenceType, const string& msg) { // TODO this gets called for giving us our current presence and message, // and also for all other resources, so we can know that the same user // is also online elsewhere printf("%s(%s, %s)\n", __PRETTY_FUNCTION__, resource.c_str(), msg.c_str()); } bool JRoster::handleSubscriptionRequest(const gloox::JID& JID, const string& reason) { BString message; if (reason.empty()) message.SetToFormat("%s would like to subscribe to your presence so they may know if " "you're online or not. Would you like to allow it?", JID.bare().c_str()); else message.SetToFormat("%s would like to subscribe to your presence so they may know if " "you're online or not. Would you like to allow it?\nThey write:\n%s", JID.bare().c_str(), reason.c_str()); gloox::Client* client = JabberSpeak::Instance()->GlooxClient(); // query for presence authorization (for users) int32 answer = 0; // TODO this uses a synchrnous alert so the gloox thread will be blocked (no other message can // be sent or received) until the alert is answered by the user. Instead we should use // asynchronous mode answer = ModalAlertFactory::Alert(message.String(), "No, I prefer privacy.", "Yes, grant them my presence!"); // send back the response if (answer == 1) { gloox::Subscription subscription(gloox::Subscription::Subscribed, JID); client->send(subscription); return true; } gloox::Subscription subscription(gloox::Subscription::Unsubscribed, JID); client->send(subscription); return false; } bool JRoster::handleUnsubscriptionRequest(const gloox::JID&, const string&) { printf("%s\n", __PRETTY_FUNCTION__); #if 0 sprintf(buffer, "%s no longer wishes to know your online status.", asker); ModalAlertFactory::NonModalAlert(buffer, "I feel so unloved."); #endif return false; } void JRoster::handleNonrosterPresence(const gloox::Presence&) { printf("%s\n", __PRETTY_FUNCTION__); } void JRoster::handleRosterError(const gloox::IQ&) { printf("%s\n", __PRETTY_FUNCTION__); } JRoster::JRoster() { _roster = new RosterList; // create semaphore _roster_lock = create_sem(1, "roster sempahore"); } void JRoster::_ProcessUserPresence(UserID *user, gloox::Presence::PresenceType type, const std::string& message) { #if 0 // get best asker name const char *asker; if (user && user->FriendlyName().size() > 0) { // they have a friendly name asker = user->FriendlyName().c_str(); } else { // they have a JID asker = entity.from().full(); } #endif // reflect presence if (user && type == gloox::Presence::Unavailable) { user->SetOnlineStatus(UserID::OFFLINE); } else if (user && type == gloox::Presence::Available) { user->SetOnlineStatus(UserID::ONLINE); } if (user && (type == gloox::Presence::Unavailable || type == gloox::Presence::Available)) { #if 0 if (entity->Child("show") && entity->Child("show")->Data()) { user->SetExactOnlineStatus(entity->Child("show")->Data()); } #endif user->SetMoreExactOnlineStatus(message); } }