1184 lines
40 KiB
C++
1184 lines
40 KiB
C++
|
|
#if defined( WIN32 )
|
|
#include <time.h>
|
|
#endif
|
|
|
|
#include <sstream>
|
|
#include "rutil/ResipAssert.h"
|
|
#include <algorithm>
|
|
#include "../Version.hxx"
|
|
#include "JabberComponent.hxx"
|
|
#include "IChatUser.hxx"
|
|
|
|
#ifndef RESIP_CONTRIB_GLOOX
|
|
#include <gloox/disco.h>
|
|
#include <gloox/mutex.h>
|
|
#include <gloox/message.h>
|
|
#else
|
|
#include <src/disco.h>
|
|
#include <src/mutex.h>
|
|
#include <src/message.h>
|
|
#endif
|
|
|
|
using namespace gateway;
|
|
using namespace gloox;
|
|
using namespace std;
|
|
|
|
extern void sleepSeconds(unsigned int seconds);
|
|
|
|
void
|
|
IChatCallRequest::sendIChatVCRequest(const std::string& fullTo)
|
|
{
|
|
// Only allow one VCRequest per resource - this guards against receiving multiple
|
|
// presence messages from the same resource
|
|
if(mPendingVCRequestSet.find(fullTo) == mPendingVCRequestSet.end())
|
|
{
|
|
mJabberComponent->notifyIChatCallProceeding(mB2BSessionHandle, fullTo);
|
|
|
|
resip_assert(mJabberComponent);
|
|
mJabberComponent->sendPresence(fullTo, mJabberComponent->mControlJID, false /* advertiseIChatSupport */, true /* available */); // Doing this let's us push the control presence as well send calls
|
|
|
|
std::string id = mJabberComponent->mComponent->getID();
|
|
|
|
Tag *iq = new Tag("iq");
|
|
iq->addAttribute("type", "set");
|
|
iq->addAttribute("id", id);
|
|
iq->addAttribute("to", fullTo.c_str());
|
|
iq->addAttribute("from", mFrom.c_str());
|
|
Tag *query = new Tag(iq, "query");
|
|
query->addAttribute("xmlns", "apple:iq:vc:request");
|
|
new Tag(query, "VCNewCallerIPPortData", mJabberComponent->mLocalIChatPortListBlob);
|
|
new Tag(query, "isAudioOnly", "1");
|
|
new Tag(query, "extSIPPort", "0");
|
|
new Tag(query, "extIPAddr", "127.0.0.1");
|
|
new Tag(query, "VCProtocolVersion", "1");
|
|
mJabberComponent->mComponent->send(iq);
|
|
|
|
mPendingVCRequestSet.insert(fullTo);
|
|
}
|
|
}
|
|
|
|
void
|
|
IChatCallRequest::receivedIChatVCResponse(const std::string& from)
|
|
{
|
|
std::set<std::string>::iterator it = mPendingVCRequestSet.find(from);
|
|
mPendingVCRequestSet.erase(it); // Remove responded JID from list and cancel all others
|
|
sendIChatVCCancelToAll();
|
|
}
|
|
|
|
void
|
|
IChatCallRequest::sendIChatVCCancelToAll()
|
|
{
|
|
std::set<std::string>::iterator it = mPendingVCRequestSet.begin();
|
|
std::string id = mJabberComponent->mComponent->getID();
|
|
|
|
// Send a cancel out for each VCRequest
|
|
for(;it!=mPendingVCRequestSet.end();it++)
|
|
{
|
|
Tag *iq = new Tag("iq");
|
|
iq->addAttribute("type", "set");
|
|
iq->addAttribute("id", id);
|
|
iq->addAttribute("to", it->c_str());
|
|
iq->addAttribute("from", mFrom.c_str());
|
|
Tag *query = new Tag(iq, "query");
|
|
query->addAttribute("xmlns", "apple:iq:vc:cancel");
|
|
new Tag(query, "VCProtocolVersion", "1");
|
|
mJabberComponent->mComponent->send(iq);
|
|
}
|
|
mPendingVCRequestSet.clear();
|
|
}
|
|
|
|
void
|
|
IChatCallRequest::sendIChatVCResponse(bool accept)
|
|
{
|
|
Tag *iq = new Tag( "iq" );
|
|
iq->addAttribute( "type", "set" );
|
|
iq->addAttribute( "id", mJabberComponent->mComponent->getID() );
|
|
iq->addAttribute( "to", mFrom );
|
|
iq->addAttribute( "from", mTo );
|
|
Tag *query = new Tag( iq, "query" );
|
|
query->addAttribute( "xmlns", "apple:iq:vc:response");
|
|
if(accept)
|
|
{
|
|
new Tag( query, "response", "0" );
|
|
new Tag( query, "connectData", mJabberComponent->mLocalIChatPortListBlob);
|
|
}
|
|
else
|
|
{
|
|
new Tag( query, "response", "1" );
|
|
new Tag( query, "connectData", "");
|
|
}
|
|
//new Tag( query, "responseData", "1" ); // doesn't appear to be required
|
|
new Tag( query, "VCProtocolVersion", "1" );
|
|
mJabberComponent->mComponent->send(iq);
|
|
}
|
|
|
|
class IPCMutexGloox : public IPCMutex
|
|
{
|
|
public:
|
|
IPCMutexGloox() {}
|
|
virtual ~IPCMutexGloox() {}
|
|
virtual void lock() { mMutex.lock(); }
|
|
virtual void unlock() { mMutex.unlock(); }
|
|
private:
|
|
gloox::util::Mutex mMutex;
|
|
};
|
|
IPCMutexGloox g_IPCGlooxMutex;
|
|
|
|
JabberComponent::JabberComponent(unsigned short jabberConnectorIPCPort,
|
|
unsigned short gatewayIPCPort,
|
|
const std::string& server,
|
|
const std::string& component,
|
|
const std::string& password,
|
|
int port,
|
|
unsigned int serverPingDuration,
|
|
const std::string& controlUser,
|
|
const std::string& localIChatPortListBlob)
|
|
: mStopping(false),
|
|
mServerPingDuration(serverPingDuration),
|
|
mLocalIChatPortListBlob(localIChatPortListBlob),
|
|
mIPCThread(jabberConnectorIPCPort, gatewayIPCPort, this, &g_IPCGlooxMutex)
|
|
{
|
|
mIPCThread.run();
|
|
|
|
mComponent = new Component("jabber:component:accept", server, component, password, port);
|
|
|
|
mComponent->registerMessageHandler(this);
|
|
mComponent->registerConnectionListener(this);
|
|
mComponent->registerPresenceHandler(this);
|
|
mComponent->registerSubscriptionHandler(this);
|
|
mComponent->registerIqHandler(this, "apple:iq:vc:request");
|
|
mComponent->registerIqHandler(this, "apple:iq:vc:cancel");
|
|
mComponent->registerIqHandler(this, "apple:iq:vc:response");
|
|
mComponent->registerIqHandler(this, "apple:iq:vc:counterProposal");
|
|
mComponent->logInstance().registerLogHandler(LogLevelDebug, LogAreaAll, this);
|
|
|
|
mComponent->disco()->registerNodeHandler(this, "apple:ichat:caps#avavail");
|
|
mComponent->disco()->registerNodeHandler(this, "apple:ichat:caps#audio");
|
|
mComponent->disco()->registerNodeHandler(this, "apple:ichat:caps#avcap");
|
|
mComponent->disco()->registerNodeHandler(this, "apple:ichat:caps#448");
|
|
mComponent->disco()->setIdentity("server", "ichat-gw");
|
|
mComponent->disco()->setVersion("ichat-gw", ICHATGW_VERSION_STRING);
|
|
|
|
//mComponent->setTls(tlsPolicy); // This setting appears to have no effect on Component connections
|
|
|
|
mControlJID = controlUser + "@" + component;
|
|
}
|
|
|
|
JabberComponent::~JabberComponent()
|
|
{
|
|
mIPCThread.shutdown();
|
|
mIPCThread.join();
|
|
}
|
|
|
|
void
|
|
JabberComponent::thread()
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::thread - starting...");
|
|
while(!mStopping)
|
|
{
|
|
mComponent->connect(false);
|
|
ConnectionError rc;
|
|
time_t lastRecvTime=time(0);
|
|
while((rc=mComponent->recv(mServerPingDuration * 1000000)) == ConnNoError)
|
|
{
|
|
time_t now = time(0);
|
|
if(now-lastRecvTime >= mServerPingDuration)
|
|
{
|
|
mComponent->whitespacePing();
|
|
}
|
|
lastRecvTime = now;
|
|
}
|
|
|
|
if(!mStopping)
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "JabberComponent::thread - recv error, rc=" << rc;
|
|
handleLog(gloox::LogLevelError, gloox::LogAreaUser, oss.str());
|
|
// Wait 10 seconds then try again
|
|
sleepSeconds(10);
|
|
if(mComponent->state() != gloox::StateDisconnected)
|
|
{
|
|
mComponent->disconnect();
|
|
}
|
|
}
|
|
}
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::thread - shutdown.");
|
|
}
|
|
|
|
void
|
|
JabberComponent::stop()
|
|
{
|
|
mStopping = true;
|
|
disconnect();
|
|
}
|
|
|
|
void
|
|
JabberComponent::disconnect()
|
|
{
|
|
if(mComponent->state() == gloox::StateDisconnected) return;
|
|
|
|
mIChatUserMutex.lock();
|
|
|
|
// Tell users that control user is now offline
|
|
IChatUserMap::iterator it = mIChatUsers.begin();
|
|
for(;it!=mIChatUsers.end();it++)
|
|
{
|
|
// Notify user that subscribed users are now offline
|
|
const IChatUser::SubscribedGatewayUserList& subscribedUserList = it->second->getSubscribedGatewayUserList();
|
|
IChatUser::SubscribedGatewayUserList::const_iterator it2 = subscribedUserList.begin();
|
|
for(;it2!=subscribedUserList.end();it2++)
|
|
{
|
|
sendPresence(it->first, *it2, false, false /* available? */);
|
|
}
|
|
delete it->second;
|
|
}
|
|
mIChatUsers.clear();
|
|
|
|
mIChatUserMutex.unlock();
|
|
|
|
mComponent->disconnect();
|
|
}
|
|
|
|
void
|
|
JabberComponent::initiateIChatCall(const std::string& to, const std::string& from, unsigned int handle, bool alertOneOnly)
|
|
{
|
|
JID jid(to);
|
|
mOutstandingClientIChatCallRequestsMutex.lock();
|
|
|
|
// Add call request data to map
|
|
std::string key = makeVCRequestKey(jid.bare(),from);
|
|
IChatCallRequest* iChatCallRequest = &(mOutstandingClientIChatCallRequests[key] = IChatCallRequest(this, to, from, handle));
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::initiateiChatCall - key=" + key);
|
|
|
|
// If there is no resource, then we need to query the bare JID and find iChat resources
|
|
if(jid.resource().empty())
|
|
{
|
|
bool found = false;
|
|
if(alertOneOnly)
|
|
{
|
|
// First check if we have any info cached locally
|
|
std::string fullJID;
|
|
if(getMostAvailableIChatUserFullJID(jid, fullJID))
|
|
{
|
|
found = true;
|
|
iChatCallRequest->sendIChatVCRequest(fullJID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::list<std::string> fullJIDList;
|
|
if(getMostAvailableIChatUserFullJIDList(jid, fullJIDList))
|
|
{
|
|
found = true;
|
|
std::list<std::string>::iterator it = fullJIDList.begin();
|
|
for(;it!=fullJIDList.end();it++)
|
|
{
|
|
iChatCallRequest->sendIChatVCRequest(*it);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!found)
|
|
{
|
|
// No local info - try to probe
|
|
Tag *iq = new Tag("presence");
|
|
iq->addAttribute("type", "probe");
|
|
iq->addAttribute("to", to.c_str());
|
|
iq->addAttribute("from", mControlJID);
|
|
mComponent->send(iq);
|
|
}
|
|
}
|
|
else // We have full JID - send the vc-request directly to the resource
|
|
{
|
|
iChatCallRequest->sendIChatVCRequest(to);
|
|
}
|
|
mOutstandingClientIChatCallRequestsMutex.unlock();
|
|
}
|
|
|
|
void
|
|
JabberComponent::cancelIChatCall(const std::string& to, const std::string& from)
|
|
{
|
|
JID jid(to);
|
|
mOutstandingClientIChatCallRequestsMutex.lock();
|
|
|
|
IChatCallRequestMap::iterator it = findOutstandingClientIChatCallRequest(jid.bare(), from);
|
|
if(it != mOutstandingClientIChatCallRequests.end())
|
|
{
|
|
it->second.sendIChatVCCancelToAll();
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::cancelIChatCall - success");
|
|
mOutstandingClientIChatCallRequests.erase(it);
|
|
}
|
|
else
|
|
{
|
|
handleLog(gloox::LogLevelWarning, gloox::LogAreaUser, "JabberComponent::cancelIChatCall - not found");
|
|
}
|
|
mOutstandingClientIChatCallRequestsMutex.unlock();
|
|
}
|
|
|
|
void
|
|
JabberComponent::proceedingIChatCall(const std::string& to, const std::string& from, unsigned int handle)
|
|
{
|
|
mOutstandingServerIChatCallRequestsMutex.lock();
|
|
IChatCallRequestMap::iterator it = findOutstandingServerIChatCallRequest(to, from);
|
|
if(it!=mOutstandingServerIChatCallRequests.end())
|
|
{
|
|
// Store session handle for notifications to SIP layer
|
|
resip_assert(it->second.mB2BSessionHandle == 0);
|
|
std::ostringstream oss;
|
|
oss << "JabberComponent::proceedingIChatCall - set handle to " << handle;
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
|
|
it->second.mB2BSessionHandle = handle;
|
|
|
|
// If already cancelled, then notify SIP layer now
|
|
if(it->second.mCancelled)
|
|
{
|
|
notifyIChatCallCancelled(it->second.mB2BSessionHandle);
|
|
mOutstandingServerIChatCallRequests.erase(it);
|
|
}
|
|
}
|
|
mOutstandingServerIChatCallRequestsMutex.unlock();
|
|
}
|
|
|
|
void
|
|
JabberComponent::acceptIChatCall(const std::string& to, const std::string& from)
|
|
{
|
|
mOutstandingServerIChatCallRequestsMutex.lock();
|
|
IChatCallRequestMap::iterator it = findOutstandingServerIChatCallRequest(to, from);
|
|
if(it!=mOutstandingServerIChatCallRequests.end())
|
|
{
|
|
it->second.sendIChatVCResponse(true);
|
|
mOutstandingServerIChatCallRequests.erase(it);
|
|
}
|
|
mOutstandingServerIChatCallRequestsMutex.unlock();
|
|
}
|
|
|
|
void
|
|
JabberComponent::rejectIChatCall(const std::string& to, const std::string& from)
|
|
{
|
|
mOutstandingServerIChatCallRequestsMutex.lock();
|
|
IChatCallRequestMap::iterator it = findOutstandingServerIChatCallRequest(to, from);
|
|
if(it!=mOutstandingServerIChatCallRequests.end())
|
|
{
|
|
it->second.sendIChatVCResponse(false);
|
|
mOutstandingServerIChatCallRequests.erase(it);
|
|
}
|
|
mOutstandingServerIChatCallRequestsMutex.unlock();
|
|
}
|
|
|
|
std::string
|
|
JabberComponent::makeVCRequestKey(const std::string& bareTo, const std::string& bareFrom)
|
|
{
|
|
std::string key = bareTo + "|" + bareFrom;
|
|
#ifdef WIN32
|
|
std::transform(key.begin(), key.end(), key.begin(), tolower);
|
|
#else
|
|
std::transform(key.begin(), key.end(), key.begin(), (int(*)(int))std::tolower);
|
|
#endif
|
|
return key;
|
|
}
|
|
|
|
JabberComponent::IChatCallRequestMap::iterator
|
|
JabberComponent::findOutstandingClientIChatCallRequest(const std::string& bareTo, const std::string& bareFrom)
|
|
{
|
|
std::string key = makeVCRequestKey(bareTo, bareFrom);
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::findOutstandingClientIChatCallRequest - key=" + key);
|
|
return mOutstandingClientIChatCallRequests.find(key);
|
|
}
|
|
|
|
void
|
|
JabberComponent::failOutstandingClientIChatCallRequest(const std::string& bareTo, const std::string& bareFrom, unsigned int code)
|
|
{
|
|
mOutstandingClientIChatCallRequestsMutex.lock();
|
|
IChatCallRequestMap::iterator it = findOutstandingClientIChatCallRequest(bareTo, bareFrom);
|
|
if(it!=mOutstandingClientIChatCallRequests.end())
|
|
{
|
|
notifyIChatCallFailed(it->second.mB2BSessionHandle, code);
|
|
mOutstandingClientIChatCallRequests.erase(it);
|
|
}
|
|
mOutstandingClientIChatCallRequestsMutex.unlock();
|
|
}
|
|
|
|
void
|
|
JabberComponent::failOutstandingClientIChatCallRequest(const std::string& bareTo, unsigned int code)
|
|
{
|
|
mOutstandingClientIChatCallRequestsMutex.lock();
|
|
IChatCallRequestMap::iterator it = mOutstandingClientIChatCallRequests.begin();
|
|
while(it != mOutstandingClientIChatCallRequests.end())
|
|
{
|
|
if(it->second.mTo == bareTo)
|
|
{
|
|
notifyIChatCallFailed(it->second.mB2BSessionHandle, code);
|
|
mOutstandingClientIChatCallRequests.erase(it++);
|
|
}
|
|
else
|
|
{
|
|
it++;
|
|
}
|
|
}
|
|
mOutstandingClientIChatCallRequestsMutex.unlock();
|
|
}
|
|
|
|
JabberComponent::IChatCallRequestMap::iterator
|
|
JabberComponent::findOutstandingServerIChatCallRequest(const std::string& bareTo, const std::string& bareFrom)
|
|
{
|
|
std::string key = makeVCRequestKey(bareTo, bareFrom);
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::findOutstandingServerIChatCallRequest - key=" + key);
|
|
return mOutstandingServerIChatCallRequests.find(key);
|
|
}
|
|
|
|
void
|
|
JabberComponent::cancelOutstandingServerIChatCallRequest(const std::string& bareTo, const std::string& bareFrom)
|
|
{
|
|
mOutstandingServerIChatCallRequestsMutex.lock();
|
|
IChatCallRequestMap::iterator it = findOutstandingServerIChatCallRequest(bareTo, bareFrom);
|
|
if(it!=mOutstandingServerIChatCallRequests.end())
|
|
{
|
|
if(it->second.mB2BSessionHandle != 0)
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::cancelOutstandingServerIChatCallRequest - to=" + bareTo + " from=" + bareFrom);
|
|
notifyIChatCallCancelled(it->second.mB2BSessionHandle);
|
|
mOutstandingServerIChatCallRequests.erase(it);
|
|
}
|
|
else
|
|
{
|
|
// We don't have a session handle yet, so flag request as cancelled,
|
|
// when session handle arrives, call notifyIChatCallCancelled and remove entry
|
|
it->second.mCancelled = true;
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::cancelOutstandingServerIChatCallRequest - no session handle yet, pending - to=" + bareTo + " from=" + bareFrom);
|
|
}
|
|
}
|
|
mOutstandingServerIChatCallRequestsMutex.unlock();
|
|
}
|
|
|
|
void
|
|
JabberComponent::probePresence(const std::string& to)
|
|
{
|
|
Tag *presence = new Tag("presence");
|
|
presence->addAttribute("type", "probe");
|
|
presence->addAttribute("to", to);
|
|
presence->addAttribute("from", mControlJID);
|
|
mComponent->send(presence);
|
|
}
|
|
|
|
void
|
|
JabberComponent::sendPresenceForRequest(const Presence& presence)
|
|
{
|
|
sendPresence(presence.from().bare(), presence.to().full(), presence.to().bare() != mControlJID, true /* available */);
|
|
}
|
|
|
|
void
|
|
JabberComponent::sendPresence(const std::string& to, const std::string& from, bool advertiseIChatSupport, bool available)
|
|
{
|
|
Tag *presence = new Tag("presence");
|
|
if(!available)
|
|
{
|
|
presence->addAttribute("type", "unavailable");
|
|
}
|
|
presence->addAttribute("to", to);
|
|
presence->addAttribute("from", from);
|
|
new Tag(presence, "priority", "0");
|
|
if(advertiseIChatSupport)
|
|
{
|
|
Tag* c = new Tag(presence, "c");
|
|
c->addAttribute("xmlns", "http://jabber.org/protocol/caps");
|
|
c->addAttribute("node", "apple:ichat:caps");
|
|
c->addAttribute("ver", "448"); // Note: Use version 448 so we don't collide with actual iChat version
|
|
c->addAttribute("ext", "avavail avcap audio");
|
|
}
|
|
mComponent->send(presence);
|
|
}
|
|
|
|
void
|
|
JabberComponent::sendSubscriptionResponse(const std::string& to, const std::string& from, bool success)
|
|
{
|
|
if(success)
|
|
{
|
|
Tag *p = new Tag( "presence" );
|
|
p->addAttribute( "type", "subscribed" );
|
|
p->addAttribute( "to", to );
|
|
p->addAttribute( "from", from );
|
|
mComponent->send( p );
|
|
|
|
mUserDb.addSubscribedJID(to.c_str(), from.c_str());
|
|
storeIChatSubscribedUser(to, from);
|
|
sendPresence(to, from, from != mControlJID, true);
|
|
|
|
// Subscribe back to client to ensure we are subscribed to client
|
|
Tag *iq = new Tag("presence");
|
|
iq->addAttribute("type", "subscribe");
|
|
iq->addAttribute("to", to);
|
|
iq->addAttribute("from", mControlJID);
|
|
mComponent->send(iq);
|
|
}
|
|
else
|
|
{
|
|
Tag *p = new Tag( "presence" );
|
|
p->addAttribute( "type", "unsubscribed" );
|
|
p->addAttribute( "to", to );
|
|
p->addAttribute( "from", from );
|
|
mComponent->send( p );
|
|
}
|
|
}
|
|
|
|
void
|
|
JabberComponent::removeIChatSubscribedUser(const std::string& user, const std::string& subscribedJID)
|
|
{
|
|
mIChatUserMutex.lock();
|
|
|
|
IChatUserMap::iterator it = mIChatUsers.find(user);
|
|
if(it != mIChatUsers.end())
|
|
{
|
|
it->second->removeSubscribedGatewayUser(subscribedJID);
|
|
}
|
|
|
|
mIChatUserMutex.unlock();
|
|
}
|
|
|
|
void
|
|
JabberComponent::storeIChatSubscribedUser(const std::string& user, const std::string& subscribedJID)
|
|
{
|
|
mIChatUserMutex.lock();
|
|
|
|
IChatUserMap::iterator it = mIChatUsers.find(user);
|
|
if(it == mIChatUsers.end())
|
|
{
|
|
// User is not yet present in map
|
|
IChatUser* iChatUser = new IChatUser(*this, user);
|
|
iChatUser->addSubscribedGatewayUser(subscribedJID);
|
|
mIChatUsers[user] = iChatUser;
|
|
}
|
|
else
|
|
{
|
|
it->second->addSubscribedGatewayUser(subscribedJID);
|
|
}
|
|
|
|
mIChatUserMutex.unlock();
|
|
}
|
|
|
|
void
|
|
JabberComponent::storeIChatPresence(const gloox::JID& jid, const gloox::Presence& presence, int priority, bool avAvail)
|
|
{
|
|
mIChatUserMutex.lock();
|
|
|
|
IChatUserMap::iterator it = mIChatUsers.find(jid.bare());
|
|
if(it == mIChatUsers.end())
|
|
{
|
|
if(presence.presence() != gloox::Presence::Unavailable && !jid.resource().empty())
|
|
{
|
|
// User is not yet present in map
|
|
IChatUser* iChatUser = new IChatUser(*this, jid.bare());
|
|
iChatUser->updateResourceInfo(jid.resource(), presence, priority, avAvail);
|
|
mIChatUsers[jid.bare()] = iChatUser;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
it->second->updateResourceInfo(jid.resource(), presence, priority, avAvail);
|
|
}
|
|
|
|
mIChatUserMutex.unlock();
|
|
}
|
|
|
|
bool
|
|
JabberComponent::getMostAvailableIChatUserFullJID(const gloox::JID& jid, std::string& fullJID)
|
|
{
|
|
bool ret = false;
|
|
mIChatUserMutex.lock();
|
|
|
|
IChatUserMap::iterator it = mIChatUsers.find(jid.bare());
|
|
if(it != mIChatUsers.end())
|
|
{
|
|
std::string resource = it->second->getMostAvailableResource();
|
|
if(!resource.empty())
|
|
{
|
|
JID temp(jid);
|
|
temp.setResource(resource);
|
|
fullJID = temp.full();
|
|
ret = true;
|
|
}
|
|
}
|
|
|
|
mIChatUserMutex.unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool
|
|
JabberComponent::getMostAvailableIChatUserFullJIDList(const gloox::JID& jid, std::list<std::string>& fullJIDList)
|
|
{
|
|
bool ret = false;
|
|
mIChatUserMutex.lock();
|
|
|
|
IChatUserMap::iterator it = mIChatUsers.find(jid.bare());
|
|
if(it != mIChatUsers.end())
|
|
{
|
|
std::list<std::string> resourceList;
|
|
if(it->second->getMostAvailableResourceList(resourceList))
|
|
{
|
|
std::list<std::string>::iterator listIt = resourceList.begin();
|
|
for(;listIt!=resourceList.end();listIt++)
|
|
{
|
|
if(!listIt->empty())
|
|
{
|
|
JID temp(jid);
|
|
temp.setResource(*listIt);
|
|
fullJIDList.push_back(temp.full());
|
|
ret = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mIChatUserMutex.unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
JabberComponent::notifyIChatCallRequest(const std::string& to, const std::string& from)
|
|
{
|
|
IPCMsg msg;
|
|
msg.addArg("notifyIChatCallRequest");
|
|
msg.addArg(to.c_str());
|
|
msg.addArg(from.c_str());
|
|
mIPCThread.sendIPCMsg(msg);
|
|
}
|
|
|
|
void
|
|
JabberComponent::notifyIChatCallCancelled(unsigned int handle)
|
|
{
|
|
IPCMsg msg;
|
|
msg.addArg("notifyIChatCallCancelled");
|
|
msg.addArg(handle);
|
|
mIPCThread.sendIPCMsg(msg);
|
|
}
|
|
|
|
void
|
|
JabberComponent::notifyIChatCallProceeding(unsigned int handle, const std::string& to)
|
|
{
|
|
IPCMsg msg;
|
|
msg.addArg("notifyIChatCallProceeding");
|
|
msg.addArg(handle);
|
|
msg.addArg(to.c_str());
|
|
mIPCThread.sendIPCMsg(msg);
|
|
}
|
|
|
|
void
|
|
JabberComponent::notifyIChatCallFailed(unsigned int handle, unsigned int statusCode)
|
|
{
|
|
IPCMsg msg;
|
|
msg.addArg("notifyIChatCallFailed");
|
|
msg.addArg(handle);
|
|
msg.addArg(statusCode);
|
|
mIPCThread.sendIPCMsg(msg);
|
|
}
|
|
|
|
void
|
|
JabberComponent::continueIChatCall(unsigned int handle, const std::string& remoteIPPortListBlob)
|
|
{
|
|
IPCMsg msg;
|
|
msg.addArg("continueIChatCall");
|
|
msg.addArg(handle);
|
|
msg.addArg(remoteIPPortListBlob.c_str());
|
|
mIPCThread.sendIPCMsg(msg);
|
|
}
|
|
|
|
void
|
|
JabberComponent::sipRegisterJabberUser(const std::string& jidToRegister)
|
|
{
|
|
IPCMsg msg;
|
|
msg.addArg("sipRegisterJabberUser");
|
|
msg.addArg(jidToRegister.c_str());
|
|
mIPCThread.sendIPCMsg(msg);
|
|
}
|
|
|
|
void
|
|
JabberComponent::sipUnregisterJabberUser(const std::string& jidToUnregister)
|
|
{
|
|
IPCMsg msg;
|
|
msg.addArg("sipUnregisterJabberUser");
|
|
msg.addArg(jidToUnregister.c_str());
|
|
mIPCThread.sendIPCMsg(msg);
|
|
}
|
|
|
|
void
|
|
JabberComponent::checkSubscription(const std::string& to, const std::string& from)
|
|
{
|
|
IPCMsg msg;
|
|
msg.addArg("checkSubscription");
|
|
msg.addArg(to.c_str());
|
|
msg.addArg(from.c_str());
|
|
mIPCThread.sendIPCMsg(msg);
|
|
}
|
|
|
|
void
|
|
JabberComponent::onNewIPCMsg(const IPCMsg& msg)
|
|
{
|
|
const std::vector<std::string>& args = msg.getArgs();
|
|
resip_assert(args.size() >= 1);
|
|
if(args.at(0) == "initiateIChatCall")
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - initiateIChatCall");
|
|
resip_assert(args.size() == 4);
|
|
initiateIChatCall(args.at(1).c_str(), args.at(2).c_str(), atoi(args.at(3).c_str()), false /* TODO - make setting? */);
|
|
}
|
|
else if(args.at(0) == "cancelIChatCall")
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - cancelIChatCall");
|
|
resip_assert(args.size() == 3);
|
|
cancelIChatCall(args.at(1).c_str(), args.at(2).c_str());
|
|
}
|
|
else if(args.at(0) == "proceedingIChatCall")
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - proceedingIChatCall");
|
|
resip_assert(args.size() == 4);
|
|
proceedingIChatCall(args.at(1).c_str(), args.at(2).c_str(), atoi(args.at(3).c_str()));
|
|
}
|
|
else if(args.at(0) == "acceptIChatCall")
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - acceptIChatCall");
|
|
resip_assert(args.size() == 3);
|
|
acceptIChatCall(args.at(1).c_str(), args.at(2).c_str());
|
|
}
|
|
else if(args.at(0) == "rejectIChatCall")
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - rejectIChatCall");
|
|
resip_assert(args.size() == 3);
|
|
rejectIChatCall(args.at(1).c_str(), args.at(2).c_str());
|
|
}
|
|
else if(args.at(0) == "sendSubscriptionResponse")
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - sendSubscriptionResponse");
|
|
resip_assert(args.size() == 4);
|
|
sendSubscriptionResponse(args.at(1).c_str(), args.at(2).c_str(), atoi(args.at(3).c_str()) != 0);
|
|
}
|
|
else
|
|
{
|
|
resip_assert(false);
|
|
}
|
|
}
|
|
|
|
void
|
|
JabberComponent::handleLog(LogLevel level, LogArea area, const std::string& message)
|
|
{
|
|
IPCMsg msg;
|
|
msg.addArg("log");
|
|
|
|
switch(level)
|
|
{
|
|
case LogLevelWarning: /**< Non-crititcal warning messages. */
|
|
msg.addArg("warning");
|
|
break;
|
|
case LogLevelError: /**< Critical, unrecoverable errors. */
|
|
msg.addArg("error");
|
|
break;
|
|
case LogLevelDebug: /**< Debug messages. */
|
|
default:
|
|
msg.addArg("info");
|
|
break;
|
|
}
|
|
msg.addArg(message.c_str());
|
|
mIPCThread.sendIPCMsg(msg);
|
|
}
|
|
|
|
void
|
|
JabberComponent::onConnect()
|
|
{
|
|
// connection established, auth done (see API docs for exceptions)
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onConnect");
|
|
|
|
// Get persisent User subscriptions - and send on-line message
|
|
const JabberUserDb::UserMap& users = mUserDb.getUserSubscriptions();
|
|
JabberUserDb::UserMap::const_iterator it = users.begin();
|
|
for(;it!=users.end();it++)
|
|
{
|
|
probePresence(it->first.c_str()); // Probe for users presence
|
|
JabberUserDb::SubscribeSet::const_iterator it2 = it->second.begin();
|
|
for(;it2!=it->second.end();it2++)
|
|
{
|
|
sendPresence(it->first.c_str(), it2->c_str(), it2->c_str() != mControlJID /* advertise iChat audio support */, true /* available */);
|
|
storeIChatSubscribedUser(it->first.c_str(), it2->c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
JabberComponent::onDisconnect(ConnectionError e)
|
|
{
|
|
// connection established, auth done (see API docs for exceptions)
|
|
std::ostringstream oss;
|
|
oss << "JabberComponent::onDisconnect - error=" << e;
|
|
if(mStopping)
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
|
|
}
|
|
else
|
|
{
|
|
handleLog(gloox::LogLevelWarning, gloox::LogAreaUser, oss.str());
|
|
}
|
|
}
|
|
|
|
bool
|
|
JabberComponent::onTLSConnect(const CertInfo& info)
|
|
{
|
|
// Note: currently gloox components to not support TLS connections
|
|
|
|
// examine certificate info
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onTLSConnect");
|
|
return true;
|
|
}
|
|
|
|
void
|
|
JabberComponent::handleSubscription(const Subscription& subscription)
|
|
{
|
|
switch( subscription.subtype() )
|
|
{
|
|
case Subscription::Subscribe:
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleSubscription - Subscribe");
|
|
if(subscription.to().full() == mControlJID)
|
|
{
|
|
sendSubscriptionResponse(subscription.from().bare(), subscription.to().full(), true);
|
|
}
|
|
else
|
|
{
|
|
checkSubscription(subscription.to().full(), subscription.from().bare());
|
|
}
|
|
break;
|
|
}
|
|
case Subscription::Unsubscribe:
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleSubscription - Unsubscribe");
|
|
Tag *p = new Tag( "presence" );
|
|
p->addAttribute( "type", "unsubscribed" );
|
|
p->addAttribute( "to", subscription.from().bare() );
|
|
p->addAttribute( "from", subscription.to().full() );
|
|
mComponent->send( p );
|
|
|
|
mUserDb.removeSubscribedJID(subscription.from().bare().c_str(), subscription.to().bare().c_str());
|
|
removeIChatSubscribedUser(subscription.from().bare(), subscription.to().bare());
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleSubscription - subtype=" + subscription.subtype());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
JabberComponent::handlePresence(const Presence& presence)
|
|
{
|
|
bool iChatResource = false;
|
|
bool avAvail=false;
|
|
|
|
// Check if iChat endpoint
|
|
Tag* c = presence.tag()->findChild("c");
|
|
if(c)
|
|
{
|
|
std::string node = c->findAttribute("node");
|
|
if(node == "apple:ichat:caps" ||
|
|
node == "http://www.apple.com/ichat/caps")
|
|
{
|
|
iChatResource = true;
|
|
|
|
// Check if caps include AV Available capability (note: if iChat is already on a call then it does not have avavail capability - since iChat only allows one call at a time)
|
|
std::string ext = c->findAttribute("ext");
|
|
if(ext.find("avavail") != std::string::npos)
|
|
{
|
|
avAvail = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// presence info
|
|
switch(presence.subtype())
|
|
{
|
|
case gloox::Presence::Probe:
|
|
// A request for an entity's current presence
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handlePresence - Probe from " + presence.from().full());
|
|
sendPresenceForRequest(presence);
|
|
break;
|
|
|
|
case gloox::Presence::Available:
|
|
// Signals to the server that the sender is online and available for communication.
|
|
|
|
if(iChatResource)
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handlePresence - PresenceAvailable from " + presence.from().full());
|
|
// Ensure we are tracking client
|
|
storeIChatPresence(presence.from(), presence, presence.priority(), avAvail);
|
|
|
|
// Check if we have an outstanding iChat Call request
|
|
if(avAvail)
|
|
{
|
|
mOutstandingClientIChatCallRequestsMutex.lock();
|
|
IChatCallRequestMap::iterator it = mOutstandingClientIChatCallRequests.begin();
|
|
bool callRequestFound = false;
|
|
while(it != mOutstandingClientIChatCallRequests.end())
|
|
{
|
|
if(it->second.mTo == presence.from().bare())
|
|
{
|
|
callRequestFound = true;
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handlePresence - Available for " + presence.from().full() + " - outstanding iChat call request - continuing call");
|
|
|
|
it->second.sendIChatVCRequest(presence.from().full());
|
|
}
|
|
it++;
|
|
}
|
|
mOutstandingClientIChatCallRequestsMutex.unlock();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case gloox::Presence::Unavailable:
|
|
// Signals that the entity is no longer available for communication.
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handlePresence - Unavailable for " + presence.from().full());
|
|
|
|
// Ensure we are tracking client
|
|
storeIChatPresence(presence.from(), presence, presence.priority(), avAvail);
|
|
|
|
// Check if we have an outstanding iChat Call request to fail
|
|
failOutstandingClientIChatCallRequest(presence.from().bare(), 404);
|
|
break;
|
|
|
|
case gloox::Presence::Error:
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handlePresence - Error for " + presence.from().full());
|
|
|
|
{
|
|
unsigned int code = 0;
|
|
Tag *error = presence.tag()->findChild( "error" );
|
|
if(error)
|
|
{
|
|
code = atoi(error->findAttribute("code").c_str());
|
|
}
|
|
|
|
// Check if we have an outstanding iChat Call request to fail
|
|
failOutstandingClientIChatCallRequest(presence.from().bare(), code);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
JabberComponent::handleMessage(const Message& msg, MessageSession* session)
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "JabberComponent::handlePresence - " << &msg;
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
|
|
Message *s = new Message(Message::Normal, msg.from().full(), "You have reached the ichat gateway!" );
|
|
s->tag()->addAttribute("from", msg.to().full());
|
|
|
|
mComponent->send(*s);
|
|
}
|
|
|
|
bool
|
|
JabberComponent::handleIq(const IQ& iq)
|
|
{
|
|
if(iq.subtype() == IQ::Set && iq.tag()->xmlns() == "apple:iq:vc:request")
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:request from=" + iq.from().full() + ", to=" + iq.to().full());
|
|
TagList tlist = iq.tag()->children();
|
|
Tag* query = iq.tag()->findChild("query");
|
|
Tag* vcNewCallerIPPortDataTag;
|
|
if(query)
|
|
{
|
|
vcNewCallerIPPortDataTag = query->findChild("VCNewCallerIPPortData");
|
|
if(vcNewCallerIPPortDataTag)
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "Jabber::handleIq: vc:request, VCNewCallerIPPortData=" << vcNewCallerIPPortDataTag->cdata() << " size=" << vcNewCallerIPPortDataTag->cdata().size();
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
|
|
}
|
|
Tag* extSIPPort = query->findChild("extSIPPort");
|
|
if(extSIPPort)
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:request extSIPPort=" + extSIPPort->cdata());
|
|
}
|
|
Tag* extIPAddr = query->findChild("extIPAddr");
|
|
if(extIPAddr)
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:request extIPAddr=" + extIPAddr->cdata());
|
|
}
|
|
Tag* vcProtocolVersion = query->findChild("VCProtocolVersion");
|
|
if(vcProtocolVersion)
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:request VCProtocolVersion=" + vcProtocolVersion->cdata());
|
|
}
|
|
}
|
|
|
|
// Create entry in outstanding server requests map
|
|
std::string key = makeVCRequestKey(iq.to().bare(),iq.from().bare());
|
|
mOutstandingServerIChatCallRequestsMutex.lock();
|
|
IChatCallRequest* iChatCallRequest = &(mOutstandingServerIChatCallRequests[key] = IChatCallRequest(this, iq.to().bare(), iq.from().full(), 0));
|
|
mOutstandingServerIChatCallRequestsMutex.unlock();
|
|
|
|
// Pass request to SIP side
|
|
notifyIChatCallRequest(iq.to().bare(), iq.from().bare());
|
|
}
|
|
else if(iq.subtype() == IQ::Set && iq.tag()->xmlns() == "apple:iq:vc:counterProposal")
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:counterProposal from=" + iq.from().full() + ", to=" + iq.to().full());
|
|
|
|
// Build response - Do we even need to respond???
|
|
{
|
|
Tag *iqtag = new Tag( "iq" );
|
|
iqtag->addAttribute( "type", "set" );
|
|
iqtag->addAttribute( "id", mComponent->getID() );
|
|
iqtag->addAttribute( "to", iq.from().full() );
|
|
iqtag->addAttribute( "from", iq.to().full() );
|
|
Tag *query = new Tag( iqtag, "query" );
|
|
query->addAttribute( "xmlns", "apple:iq:vc:counterProposal");
|
|
new Tag( query, "connectData", mLocalIChatPortListBlob);
|
|
new Tag( query, "VCProtocolVersion", "1" );
|
|
mComponent->send(iq);
|
|
}
|
|
}
|
|
else if(iq.subtype() == IQ::Set && iq.tag()->xmlns() == "apple:iq:vc:cancel")
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:cancel from=" + iq.from().full() + ", to=" + iq.to().full());
|
|
cancelOutstandingServerIChatCallRequest(iq.to().bare(), iq.from().bare());
|
|
}
|
|
else if(iq.subtype() == IQ::Set && iq.tag()->xmlns() == "apple:iq:vc:response")
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:response from=" + iq.from().full() + ", to=" + iq.to().full());
|
|
TagList tlist = iq.tag()->children();
|
|
Tag* query = iq.tag()->findChild("query");
|
|
Tag* vcNewCallerIPPortDataTag;
|
|
if(query)
|
|
{
|
|
vcNewCallerIPPortDataTag = query->findChild("connectData");
|
|
if(vcNewCallerIPPortDataTag)
|
|
{
|
|
mOutstandingClientIChatCallRequestsMutex.lock();
|
|
|
|
std::ostringstream oss;
|
|
oss << "Jabber::handleIq - connectData=" << vcNewCallerIPPortDataTag->cdata() << " size=" << vcNewCallerIPPortDataTag->cdata().size();
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
|
|
|
|
IChatCallRequestMap::iterator it = findOutstandingClientIChatCallRequest(iq.from().bare(), iq.to().bare());
|
|
if(it!=mOutstandingClientIChatCallRequests.end())
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:response received - continuing SIP portion of call...");
|
|
it->second.receivedIChatVCResponse(iq.from().full());
|
|
continueIChatCall(it->second.mB2BSessionHandle, vcNewCallerIPPortDataTag->cdata());
|
|
mOutstandingClientIChatCallRequests.erase(it);
|
|
}
|
|
mOutstandingClientIChatCallRequestsMutex.unlock();
|
|
}
|
|
}
|
|
}
|
|
else if(iq.subtype() == IQ::Error && iq.tag()->xmlns() == "apple:iq:vc:request")
|
|
{
|
|
unsigned int code = 0;
|
|
Tag *error = iq.tag()->findChild( "error" );
|
|
if(error)
|
|
{
|
|
code = atoi(error->findAttribute("code").c_str());
|
|
}
|
|
|
|
failOutstandingClientIChatCallRequest(iq.from().bare(), iq.to().bare(), code);
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:request error received - notifying SIP portion of call...");
|
|
}
|
|
else
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "Jabber::handleIq - " << &iq;
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
JabberComponent::handleIqID(const IQ& iq, int context)
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "Jabber::handleIqID - context=" << context;
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
|
|
//return false;
|
|
}
|
|
|
|
StringList
|
|
JabberComponent::handleDiscoNodeFeatures(const JID& from, const std::string& node)
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleDiscoNodeFeatures - node=" + node);
|
|
StringList slist;
|
|
if(node == "apple:ichat:caps#avavail")
|
|
{
|
|
slist.push_back("apple:iq:vc:available");
|
|
}
|
|
else if(node == "apple:ichat:caps#audio")
|
|
{
|
|
slist.push_back("apple:iq:vc:audio");
|
|
}
|
|
else if(node == "apple:ichat:caps#avcap")
|
|
{
|
|
slist.push_back("apple:iq:vc:capable");
|
|
}
|
|
else if(node == "apple:ichat:caps#448")
|
|
{
|
|
slist.push_back("jabber:iq:version");
|
|
}
|
|
return slist;
|
|
}
|
|
|
|
Disco::IdentityList
|
|
JabberComponent::handleDiscoNodeIdentities(const JID& from, const std::string& node)
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleDiscoNodeIdentities - node=" + node + ", JID=" + from.full());
|
|
Disco::IdentityList smap;
|
|
//smap["client"] = "pc";
|
|
return smap;
|
|
}
|
|
|
|
Disco::ItemList
|
|
JabberComponent::handleDiscoNodeItems(const JID& from, const JID& to, const std::string& node)
|
|
{
|
|
handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleDiscoNodeItems - node=" + node);
|
|
Disco::ItemList dlist;
|
|
return dlist;
|
|
}
|
|
|
|
|
|
/* ====================================================================
|
|
|
|
Copyright (c) 2009, SIP Spectrum, Inc.
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are
|
|
met:
|
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
3. Neither the name of SIP Spectrum nor the names of its contributors
|
|
may be used to endorse or promote products derived from this
|
|
software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
==================================================================== */
|
|
|