gloox开发

1、服务器环境

服务器是在xp系统下安装的(我是在虚拟机中的xp系统下安装的),服务器采用的是Openfire 3.9.3版本,安装服务器时采用的是服务器自带的数据库。

2、编程环境

编程环境是在win7 64位系统下进行的,采用的是Microsoft Visual Studio 2010 旗舰版进行编程。

3、客户端编程采用的技术

3.1采用基于C++实现的XMPP协议客户端开源库gloox

gloox简介:

gloox是一个开源的跨平台的C++实现的XMPP协议开发包,目前的版本为1.0.10测试版。

XMPP协议只是一个协议,一个约定,但本身并没有提供实现方式。也就是说,XMPP定义的那些关键字以及发送消息这些是需要实现的,只要按照XMPP协议来做的话,就可以互通消息了。而gloox就是实现这样一个协议的开发包,我们可以通过这个开发包,开发自己的应用来。

那么gloox如何实现了XMPP协议的呢,其实它的底层就是一个socket在收发数据,然后将数据进行XML解析,封装就可以了。

我采用的是gloox 0.9.9.12版本,可以在这里下载点击打开链接

在Microsoft Visual Studio 2010 旗舰版下编译生成了相应的动态库。

 

3.2下面介绍下如何把gloox中的源代码加入到工程中去:

自己新建一个工程,然后在工程中新建一个文件夹,我这里叫src,然后将gloox0.9.9.12 文件夹下的src文件夹中的除tests、example等文件夹外所有的文件拷贝到这里新建的src文件夹下。然后将先前编译生成的gloox.lib和gloox.dll文件拷贝到工程下。

 

我这里新建的个是一个win32控制台应用程序,应用程序类型为DLL的工程,目的是为了将所有对XMPP通信的操作都在该动态库中完成,与对窗口的操作进行分开。

 

下面开始为该工程添加文件,完成即时通信中的用户注册、登录、修改密码、修改个人资料,显示好友列表、添加联系人、聊天信息的发送和接收、创建聊天室、传送文件、视频等功能。

用户注册

</pre><pre name="code" class="cpp">#include "./src/client.h"
#include "./src/connectionlistener.h"
#include "./src/registration.h"
#include "./src/logsink.h"
#include "./src/loghandler.h"

using namespace gloox;
#include <iostream>
#include "afxmt.h"

class RegTest : public RegistrationHandler, ConnectionListener, LogHandler
{
  public:
    RegTest(bool ischangePassword) ;
    virtual ~RegTest();

   void start(CString serverName,CString userName,CString pwd);
   virtual void onConnect();
   virtual void onDisconnect( ConnectionError e );
   virtual bool onTLSConnect( const CertInfo& info );
   virtual void handleRegistrationFields( const JID& /*from*/, int fields, std::string instructions );
   virtual void handleRegistrationResult( const JID& /*from*/, RegistrationResult result );
   virtual void handleAlreadyRegistered( const JID& /*from*/ );
   virtual void handleDataForm( const JID& /*from*/, const DataForm& /*form*/ );
   virtual void handleOOB( const JID& /*from*/, const OOB& oob );
   virtual void handleLog( LogLevel level, LogArea area, const std::string& message );

  private:
    Registration *m_reg;
    Client *j;
	CString user_name;
	CString pwd_name;
	BOOL m_isChangePassword;	
};
#include"RegisterImpl.h"

RegTest::RegTest(bool ischangePassword) 
{
	user_name.Empty();
	pwd_name.Empty();
/*下面的变量用于修改密码时,判断密码是否修改,若修改了就得断开连接*/
	m_isChangePassword = ischangePassword;
}

RegTest::~RegTest() 
{
}

void RegTest::start(CString serverName,CString userName,CString pwd)
{
	user_name = userName;
	pwd_name = pwd;

	const std::string server = serverName.operator LPCTSTR();
	/*注意下面这行代码,当要注册用户时,Client中的变量需要用服务器名,与登录时不同,登录时用的是用户的JID*/
	j = new Client( server);
	j->disableRoster();
	j->registerConnectionListener( this );

	/*下面就是以服务器的指针来创建注册用户的指针,用得到的指针来注册Handler*/
<span style="white-space:pre">	</span>m_reg = new Registration( j );
	m_reg->registerRegistrationHandler( this );

	j->logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this );

	j->connect();

	delete( m_reg );
	delete( j );
}


void RegTest::onConnect()
{
	/*调用该函数能触发虚函数handleRegistrationFields*/
	m_reg->fetchRegistrationFields();
}

void RegTest::onDisconnect( ConnectionError e ) 
{ printf( "register_test: disconnected: %d\n", e ); }

bool RegTest::onTLSConnect( const CertInfo& info )
{
	printf( "status: %d\nissuer: %s\npeer: %s\nprotocol: %s\nmac: %s\ncipher: %s\ncompression: %s\n",
		info.status, info.issuer.c_str(), info.server.c_str(),
		info.protocol.c_str(), info.mac.c_str(), info.cipher.c_str(),
		info.compression.c_str() );
	return true;
}
/*在该函数中完成注册用户*/
void RegTest::handleRegistrationFields( const JID& /*from*/, int fields, std::string instructions )
{
	printf( "fields: %d\ninstructions: %s\n", fields, instructions.c_str() );
	RegistrationFields vals;
	vals.username = user_name;
	vals.password = pwd_name;
	m_reg->createAccount( fields, vals );
}

void RegTest::handleRegistrationResult( const JID& /*from*/, RegistrationResult result )
{
	printf( "result: %d\n", result );
	if(!m_isChangePassword)
	{
		j->disconnect();
	}
}

void RegTest::handleAlreadyRegistered( const JID& /*from*/ )
{
	printf( "the account already exists.\n" );
}

void RegTest::handleDataForm( const JID& /*from*/, const DataForm& /*form*/ )
{
	printf( "datForm received\n" );
}

void RegTest::handleOOB( const JID& /*from*/, const OOB& oob )
{
	printf( "OOB registration requested. %s: %s\n", oob.desc().c_str(), oob.url().c_str() );
}

void RegTest::handleLog( LogLevel level, LogArea area, const std::string& message )
{
	printf("log: level: %d, area: %d, %s\n", level, area, message.c_str() );
}

登录服务器

要想连接服务器,通常需要下面几个信息:服务器地址(域名或者 IP 地址),服务器端口号,用户帐号,用户密码。在 XMPP 协议中,服务器建议的端口号为5222, 如果没其它必要, 建议采用该端口号。 XMPP 的用户帐号别名叫 JID, JID 惟一确定进行即时消息和在线状态信息通信的独立对象或实体, 并可兼容其他即时通信系统( 如 MSN 等) 相应的实体标识及其在线状态信息。其语法规则为: [节点″@″] 域名[″/″资源], 其中各个域的长度不能超过 1 023字节, 总长度最大为 3 071 字节。从 JID 的定义可以看出来,其实要连接到服务器,JID 中就已经含有了服务器的地址,而如果默认采用 5222 端口号的话,则可以不用提供服务器地址和端口就可以了,而只通过 JID 就可以和服务器连接上。

class MessageTest : public ConnectionListener 
{ 
  public: 
    MessageTest()  {} 
    virtual ~MessageTest() {} 
    void start() 
    { 
       //初始化一个 JID,即用户 ID 
        JID jid( "userTest@serverTest/test" );   
<span style="white-space:pre">	</span>//创建一个连接客户端,后一个参数为密码 
        j = new Client( jid, "testPassword" );  
<span style="white-space:pre">	</span>/*注册连接状态监听器,当调用该方法后, gloox 会在后台自动调用该接口实现中的相应方法。 */
       j->registerConnectionListener( this );   /*这里用this参数是因为 this 中实现了ConnectionListener 接口,onConnect() 等虚函数函数 */
 <span style="white-space:pre">	</span>//设置服务
      j->disco()->setVersion( "messageTest", GLOOX_VERSION, "Linux" );                
      j->disco()->setIdentity( "client", "bot" ); 
       //关于数字证书认证方面的东东,照抄就行了。 
      StringList ca; 
      ca.push_back( "/path/to/cacert.crt" ); 
      j->setCACerts( ca ); 
      /*调用 j->connect(false)时,即实现与服务器的连接,即登陆了,连接成功会返回为真。Connect 函数参数为 false 表示不阻塞方式连接,而如果为真,则为阻塞方式连接 */
      if( j->connect( false ) ) 
      {         
      }       
    } 
    //该该方法即为实现 ConnectionListener 监听器接口中的连接成功的方法实现。 
    virtual void onConnect() 
    { 
      printf( "连接服务器成功!!!\n" ); 
    } 
/*该该方法即为实现 ConnectionListener 监听器接口中的连接失败或者 断开网络的方法实现*/
    virtual void onDisconnect( ConnectionError e ) 
    {       printf( "断开连接: %d\n", e ); 
         delete( j );          
    } 
/*该该方法即为实现 ConnectionListener 监听器接口中的安全连接成功的方法实现。 */
    virtual bool onTLSConnect( const CertInfo& info ) 
    {      
      return true; 
    } 
  private: 
    Client *j;//客户端实例对象     
}; 
int main( int /*argc*/, char** /*argv*/ )//测试代码 
{ 
  MessageTest *r = new MessageTest(); 
  r->start(); 
  delete( r ); 
  return 0; 
} 

考虑到修改密码、修改个人资料,显示好友列表、添加联系人、聊天信息的发送和接收、创建聊天室、传送文件、视频等功能的实现都是在连接登录后才能进行操作,我这里就将登录部分单独出来

#include "./src/connectionlistener.h"

class CQTalkClient;	//这个类是一个负责与客户端窗口交流的类,后面会给出
using namespace gloox;
/
// CQTalkConnectionListener

class CQTalkConnectionListener : public gloox::ConnectionListener
{
// Construction
public:
	CQTalkConnectionListener();
	CQTalkConnectionListener( CQTalkClient* pClient );
	virtual ~CQTalkConnectionListener();

// Override
public:
	virtual void onConnect();
	virtual void onDisconnect(ConnectionError e );
	virtual bool onTLSConnect( const CertInfo& info );

private:
	CIMClient* m_pClient;
};

CQTalkConnectionListener::CQTalkConnectionListener()
{
}

CQTalkConnectionListener::CQTalkConnectionListener( CQTalkClient* pClient )
{
	m_pClient = NULL;
	ASSERT( pClient );

	m_pClient = pClient;
}

CQTalkConnectionListener::~CQTalkConnectionListener()
{
}

/
// CQTalkConnectionListener override implementation

void CQTalkConnectionListener::onConnect()
{
	ASSERT( m_pClient != NULL );
	if ( m_pClient != NULL )
	{
		m_pClient->OutputLogInfo( "Connecting QTalk server !", CQTalkLogConsole::TEXT_WHITE );
	}

}

void CQTalkConnectionListener::onDisconnect( ConnectionError e )
{
ASSERT( m_pClient != NULL );

	switch ( e )
	{
	case gloox::ConnNoError :
		m_pClient->OutputLogInfo( "Not really an error. Everything went just fine.", CQTalkLogConsole::TEXT_WHITE );
		break;

	case gloox::ConnStreamError :
		m_pClient->OutputLogInfo( "A stream error occured. The stream has been closed.", CQTalkLogConsole::TEXT_WHITE );
		break;

	case gloox::ConnStreamClosed :
		m_pClient->OutputLogInfo( "The stream has been closed graciously.", CQTalkLogConsole::TEXT_WHITE );
		break;

	case gloox::ConnIoError :
		m_pClient->OutputLogInfo( "An I/O error occured.", CQTalkLogConsole::TEXT_WHITE );
		break;

	case gloox::ConnOutOfMemory :
		m_pClient->OutputLogInfo( "Out of memory. Uhoh.", CQTalkLogConsole::TEXT_WHITE );
		break;

	case gloox::ConnNoSupportedAuth :
		m_pClient->OutputLogInfo( "The auth mechanisms the server offers are not supported" \
									"or the server offered no auth mechanisms at all.", CQTalkLogConsole::TEXT_WHITE );
		break;

	case gloox::ConnTlsFailed :
		m_pClient->OutputLogInfo( "The server's certificate could not be verified.", CQTalkLogConsole::TEXT_WHITE );
		break;

	case gloox::ConnAuthenticationFailed :
		m_pClient->OutputLogInfo( "Authentication failed. Username/password wrong or account does not exist.", CQTalkLogConsole::TEXT_WHITE );
		break;

	case gloox::ConnUserDisconnected :
		m_pClient->OutputLogInfo( "The user (or higher-level protocol) requested a disconnect.", CQTalkLogConsole::TEXT_WHITE );
		break;

	case gloox::ConnNotConnected :
		m_pClient->OutputLogInfo( "There is no active connection.", CQTalkLogConsole::TEXT_WHITE );
		break;
	}
}

bool CQTalkConnectionListener::onTLSConnect( const CertInfo& info  )
{
	return true;
}

现在我建立一个类CQTalkClient,用来沟通窗口和gloox的内部:

在该类中定义了一个函数用于连接服务器,以及完成gloox所有的注册

BOOL CQTalkClient::Connect( CString strID, CString strJID, CString strPwd )
{
	OutputLogInfo( "QTalk applictaion initailze successful !", CQTalkLogConsole::TEXT_WHITE );

	ASSERT( ! strID.IsEmpty()  );
	ASSERT( ! strJID.IsEmpty() );
	ASSERT( ! strPwd.IsEmpty() );
	if ( strID.IsEmpty() || strJID.IsEmpty() || strPwd.IsEmpty() )
		return FALSE;

	setlocale( LC_ALL, "" );

	const std::string jabberID = strJID.operator LPCTSTR();
	const std::string password = strPwd.operator LPCTSTR();

	gloox::JID jid( jabberID);

	jid.setResource("QTalk");

   <span style="white-space:pre">	</span> m_pJabberClient = new gloox::Client( jid, password );

		ASSERT( m_pJabberClient != NULL );
	if ( m_pJabberClient == NULL )
		return FALSE;

	m_pQTalkDiscoHandler    = new CQTalkDiscoHandler      ();
	/*下面得到好友列表相关类指针*/
<span style="white-space:pre">	</span>m_pQTalkRosterListener  = new CQTalkRosterListener	  ( this );
<span style="white-space:pre">	</span>/*下面得到Log相关类指针*/
<span style="white-space:pre">	</span>m_pQTalkLogHandler      = new CQTalkLogHandler        ( this );
<span style="white-space:pre">	</span>/*下面得到会话相关类指针*/
	m_pQTalkSessionHandler  = new CQTalkSessionHandler    ( this );
	/*下面得到连接相关类指针*/
	m_pQTalkConnectListener = new CQTalkConnectionListener( this );
	/*下面得到聊天室相关类指针*/
	m_pQTalkRoom			= new QtalkMucRoom  (this);


	/*下面得到文件传输相关类指针*/
	m_pQTalkIBBHandler      = new CQTalkIBBHandler        ( this );


	ASSERT( m_pQTalkDiscoHandler    != NULL );
	ASSERT( m_pQTalkRosterListener  != NULL );
	ASSERT( m_pQTalkLogHandler      != NULL );
	ASSERT( m_pQTalkSessionHandler  != NULL );
	ASSERT( m_pQTalkConnectListener != NULL );
	ASSERT( m_pQTalkIBBHandler      != NULL );

	//m_pJabberClient->setPresence( PresenceAvailable );
<span style="white-space:pre">	</span>//	m_pJabberClient->setInitialPriority( 4 );
	/*注册连接状态监听器,当调用该方法后, gloox 会在后台自动调用该接口实现中的相应方法。 */
	m_pJabberClient->registerConnectionListener( m_pQTalkConnectListener );
	/*注册好友列表监听器*/
	m_pJabberClient->rosterManager()->registerRosterListener( m_pQTalkRosterListener );
	m_pJabberClient->disco()->setVersion( "QTalk", GLOOX_VERSION ,"Windows");
	m_pJabberClient->disco()->setIdentity( "client", "Qtalk" );
	/*注册log监听器*/
	m_pJabberClient->logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, m_pQTalkLogHandler );
	/*注册聊天室监听器*/
	m_pJabberClient->registerMUCInvitationHandler( m_pQTalkRoom );
/*注册会话消息监听器*/
	m_pJabberClient->registerMessageSessionHandler(m_pQTalkSessionHandler);


	if ( m_pJabberClient->connect( false ) == false )
	{
		ReleaseRes();
		return FALSE;
	}
<span style="white-space:pre">	</span>/*戏码得到名片相关类的指针*/
	m_pQTalkVCard = new VCardTest(this);

	/*下面得到文件管理相关类指针*/
	m_pIBBManager = new gloox::InBandBytestreamManager( m_pJabberClient, m_pJabberClient->disco() );
	/*注册文件传输的监听器*/
	m_pIBBManager->registerInBandBytestreamHandler( m_pQTalkIBBHandler );

	m_jid = jabberID;
	AfxGetMainWnd()->SetWindowText( m_jid.c_str() );

	/*下面是一个线程,该线程用于接收发过来的信息和数据*/
	m_pQTalkThread = AfxBeginThread( QTalkMsgHandlerProc, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED );
	ASSERT_VALID( m_pQTalkThread );
	if ( ! m_pQTalkThread )
		return FALSE;

	m_pQTalkThread->ResumeThread();

	OutputLogInfo( "Connect server successful !", CQTalkLogConsole::TEXT_WHITE );

	return TRUE;
}


线程函数的实现:
UINT CQTalkClient::QTalkMsgHandlerProc( LPVOID lParam )
{
	CQTalkClient* pQTalkClient = static_cast< CQTalkClient* >( lParam );
	ASSERT( pQTalkClient != NULL );
	if ( pQTalkClient == NULL )
		return 1;

	pQTalkClient->OutputLogInfo( "Start LISTENER thread !", CQTalkLogConsole::TEXT_RED );

	ASSERT( pQTalkClient->m_pQTalkDiscoHandler    != NULL );
	ASSERT( pQTalkClient->m_pQTalkLogHandler      != NULL );
	ASSERT( pQTalkClient->m_pQTalkSessionHandler  != NULL );
	ASSERT( pQTalkClient->m_pQTalkConnectListener != NULL );
	ASSERT( pQTalkClient->m_pJabberClient         != NULL );

	gloox::ConnectionError ce = gloox::ConnNoError;

	while ( TRUE )
	{
		DWORD dwFlag = ::WaitForSingleObject( CQTalkClient::s_QTalkEvent.m_hObject, 0 );
		if ( dwFlag == WAIT_OBJECT_0 )
		{
			pQTalkClient->OutputLogInfo( "End LISTENER thread !", CQTalkLogConsole::TEXT_RED );
			break;
		}
		ce = pQTalkClient->m_pJabberClient->recv();
	}

	return 0;
}

修改用户登录密码

在CQTalkClient函数中添加一个函数用于修改密码

VOID CQTalkClient::SetPassword(CString password)
{
	const std::string pwd = password.operator LPCTSTR();
	rr = new RegTest(TRUE);
	//rr->changepassword(serverName,useName,password);
	Registration *m_reg = new Registration(m_pJabberClient);
	m_reg->registerRegistrationHandler(rr);
	m_reg->changePassword( m_pJabberClient->username(), password.operator LPCTSTR() );
	::MessageBox(NULL,"修改密码成功!",NULL,0);
	delete (m_reg);
}

修改个人资料

#include "./src/client.h"
#include "./src/connectionlistener.h"
#include "./src/disco.h"
#include "./src/stanza.h"
#include "./src/gloox.h"
#include "./src/loghandler.h"
#include "./src/vcardhandler.h"
#include "./src/vcardmanager.h"
#include "./src/vcard.h"
using namespace gloox;

#include <stdio.h>
#include <locale.h>
#include <string>


class CQTalkClient;

struct vcard_info
{
	std::string username;
	std::string servername;
	std::string nickname;
//		std::list<VCard::Address> AddressList;
	std::string street;
	std::string family; 
	std::string given; 
	std::string middle; 
};

class VCardTest: public VCardHandler/*,ConnectionListener*/
{
public:
	VCardTest(void);
	VCardTest(CQTalkClient* pClient);

	~VCardTest(void);

public:
	void start(CString m_strjid);

	void store(CString &,CString &,CString &);

	//virtual void onConnect();
	//virtual void onDisconnect( ConnectionError e ) ;
	//virtual bool onTLSConnect( const CertInfo& info );
	//virtual void handleDiscoInfoResult( Stanza */*stanza*/, int /*context*/ );
	//virtual void handleDiscoItemsResult( Stanza */*stanza*/, int /*context*/ );
	virtual void handleDiscoError( Stanza */*stanza*/, int /*context*/ );
	//virtual void handleLog( LogLevel level, LogArea area, const std::string& message );
	virtual void handleVCard( const JID& jid, VCard *vcard);
	virtual void handleVCardResult(VCardContext context, const JID& jid,StanzaError se = StanzaErrorUndefined  );

	//Client *j;
	VCardManager *m_vManager;
	int m_count;
	CString strJID;
public:
	struct vcard_info *str;
//	static CString m_strFetch;
	CString m_strSet;
//	AddressList& m_addressList;
	BOOL	m_choice;
private:
	CQTalkClient* m_pClient;
};

VCardTest::VCardTest(void)
{

//	m_pClient = NULL;
}

VCardTest::VCardTest(CQTalkClient* pClient)
{
//	m_count = 0;
	str = NULL;
	strJID.Empty();
	m_pClient = pClient;
	m_choice = TRUE;
	m_vManager = new VCardManager( m_pClient->GetClient());
}

VCardTest::~VCardTest(void)
{
	delete(m_vManager);
}


void VCardTest::start(CString m_strjid)
{
	strJID = m_strjid;
	std::string strjid = m_strjid.operator LPCTSTR();
	JID jid( strjid );
	m_vManager->fetchVCard( strjid, this );
}

void VCardTest::store(CString &nickname,CString &servername,CString &street)
{
	std::string m_strjid = strJID.operator LPCTSTR();
	JID jid(m_strjid);

	VCard *v = new VCard();
	v->setFormattedname( "Hurk the Hurk" );
	v->setNickname( nickname.operator LPCTSTR());
	v->setName( "Simpson", "Bart", "", "Mr.", "jr." );
	v->addAddress( "pobox", "app. 2", (street.operator LPCTSTR()), "Springfield", "region", "123", "USA", VCard::AddrTypeHome );
	m_vManager->storeVCard( v, this );
	m_vManager->fetchVCard( m_strjid, this );
}

void VCardTest::handleVCard( const JID& jid, VCard *vcard )
{


	std::string m_strjid = strJID.operator LPCTSTR();
//	++m_count;
	if( !vcard )
	{
		printf( "empty vcard!\n" );
		return;
	}
	printf( "received vcard for %s: %s\n", jid.full().c_str(), vcard->tag()->xml().c_str());
//	::AfxMessageBox(jid.full().c_str());
//	::AfxMessageBox(vcard->tag()->xml().c_str());

//		m_vManager->fetchVCard( jid, this );
	str = new vcard_info;
	str ->username = jid.username().c_str();
	str ->servername = jid.server().c_str();
	str ->nickname = vcard->nickname().c_str();

	str->family = vcard->name().family;
	str->given = vcard->name().given;
	str->middle = vcard->name().middle;

	VCard::AddressList::const_iterator it = vcard->addresses().begin();
	for( ; it != vcard->addresses().end(); ++it )
	{
		//		printf( "address: %s\n", (*it).street.c_str() );
		str ->street = (*it).street.c_str();
	}

	AfxGetMainWnd()->SendMessage( \
		QTalkGlobal::WM_QTALK_VCARD, \
		NULL, \
		(LPARAM)str );
	delete(str);

}

void VCardTest::handleVCardResult( VCardContext context, const JID& jid,StanzaError se)
{
	//se = StanzaErrorUndefined;
	//printf( "vcard result: context: %d, jid: %s, error: %d\n", context, jid.full().c_str(), se );
//	m_vManager->fetchVCard( jid, this );
}

然后只需在CQTalkClient中添加一个函数:

VOID CQTalkClient::VCard(CString m_strjid/*,CString m_strPwd*/)
{
	m_pQTalkVCard->start(m_strjid);
}


添加联系人

在CQTalkClient中添加函数

VOID CQTalkClient::AddConnecter(CString m_jid,CString m_group)
{
	m_cf = TRUE;
	m_delete = FALSE;
	const std::string m_strjid = m_jid.operator LPCTSTR();
	m_strGroup = m_group;
	JID jid(m_strjid);
	m_pJabberClient->rosterManager()->subscribe(jid);
}

关于添加联系人的类:

#include "./src/rosterlistener.h"
#include "./src/rostermanager.h"

class CQTalkClient;

using namespace gloox;

class CQTalkRosterListener : public gloox::RosterListener
{
// Construction
public:
	CQTalkRosterListener();

	CQTalkRosterListener( CQTalkClient* pClient);

	virtual ~CQTalkRosterListener();

// Implementation
private:
	virtual void handleItemSubscribed  ( const JID& jid );

	virtual void handleItemUnsubscribed( const JID& jid);

	virtual void handleItemAdded ( const JID& jid );

	virtual void handleItemRemoved( const JID& jid );

	virtual void handleItemUpdated( const JID& jid );

	virtual void handleRoster( const Roster& roster );

	virtual void handleRosterPresence( const RosterItem& item, const std::string& resource,Presence presence, const std::string& msg );

	virtual bool handleSubscriptionRequest  ( const JID& jid, const std::string& msg );

	virtual bool handleUnsubscriptionRequest( const JID& jid, const std::string& msg );

	virtual void handleRosterError( Stanza* stanza );

	virtual void handleNonrosterPresence( Stanza* stanza );

	virtual void handleSelfPresence( const RosterItem& item, const std::string& resource,Presence presence, const std::string& msg );



// Implementation
private:
	CQTalkClient* m_pClient;
};

CQTalkRosterListener::CQTalkRosterListener()
{
	m_pClient = NULL;
}

CQTalkRosterListener::CQTalkRosterListener(CQTalkClient* pClient )
{
     m_pClient=pClient;
}

CQTalkRosterListener::~CQTalkRosterListener()
{
}

/
// CQTalkRosterListener method implementation

void CQTalkRosterListener::handleItemSubscribed( const JID& jid )
{
	m_pClient->OutputLogInfo( "RosterListener::itemSubscribed", CQTalkLogConsole::TEXT_WHITE );
	AfxGetMainWnd()->PostMessage( \
					QTalkGlobal::WM_QTALK_MESSAGE, \
					QTalkGlobal::WM_QTALK_ROSTER, \
					QTalkGlobal::ROSTER_LIST_ALL );
//	m_pClient->m_cf = FALSE;
}

void CQTalkRosterListener::handleItemUnsubscribed(const JID& jid)
{

}

void CQTalkRosterListener::handleItemAdded( const JID& jid )
{
	m_pClient->OutputLogInfo( "RosterListener::itemAdded", CQTalkLogConsole::TEXT_WHITE );

	RosterItem* rostitem = m_pClient->GetClient()->rosterManager()->getRosterItem(jid);
	QTalkGlobal::ROSTER rosterItem;
	rosterItem.jid         = rostitem->jid();
	rosterItem.name        = rostitem->name();
	rosterItem.subsciption = rostitem->subscription();
	rosterItem.groups.push_back((m_pClient->m_strGroup).operator LPCTSTR());
	m_pClient->m_rosterList.push_back( rosterItem );

	StringList g;
	g.push_back((m_pClient->m_strGroup).operator LPCTSTR());

	m_pClient->GetClient()->rosterManager()->add(jid,rostitem->name(),g);
}

void CQTalkRosterListener::handleItemRemoved(const JID& jid )
{
	m_pClient->OutputLogInfo( "RosterListener::itemRemoved", CQTalkLogConsole::TEXT_WHITE );
	if(m_pClient->m_delete)
	{
		QTalkGlobal::CIT_ROSTER_LIST i;
		i = m_pClient->m_rosterList.begin();
		while(i != m_pClient->m_rosterList.end())
		{
			QTalkGlobal::ROSTER rosterItem = *i;
			if(rosterItem.jid == jid.full())
			{
				m_pClient->m_rosterList.erase(i++);
			}
			else
			{
				i++;
			}
		}

		AfxGetMainWnd()->SendMessage( \
						QTalkGlobal::WM_QTALK_MESSAGE, \
						QTalkGlobal::WM_QTALK_ROSTER, \
						QTalkGlobal::ROSTER_DELETE_ITEM );
	}
}

void CQTalkRosterListener::handleItemUpdated( const JID& jid)
{
	m_pClient->OutputLogInfo( "RosterListener::itemUpdated", CQTalkLogConsole::TEXT_WHITE );

	if(!m_pClient->m_cf)
	{
		AfxGetMainWnd()->PostMessage( \
			QTalkGlobal::WM_QTALK_MESSAGE, \
			QTalkGlobal::WM_QTALK_ROSTER, \
			QTalkGlobal::ROSTER_LIST_ALL );
//		m_pClient->m_cf = TRUE;
	}
}



// By calling this method
//  you can get all roster from the server

void CQTalkRosterListener::handleRoster( const Roster& roster )
{
	m_pClient->OutputLogInfo( "Manager the roster !", CQTalkLogConsole::TEXT_WHITE );

	Roster::const_iterator it = roster.begin();

	m_pClient->m_rosterList.clear();
	QTalkGlobal::ROSTER rosterItem;

	for ( ; it != roster.end(); it++ )
	{
			m_pClient->OutputLogInfo((*it).second->jid().c_str(),CQTalkLogConsole::TEXT_PURPLE );
			m_pClient->OutputLogInfo((*it).second->name().c_str(), CQTalkLogConsole::TEXT_PURPLE );
			//m_pClient->OutputLogInfo((*it).second->subscription(), CQTalkLogConsole::TEXT_PURPLE );

			StringList g = (*it).second->groups();
			StringList::const_iterator it_g = g.begin();
			for( ; it_g != g.end(); ++it_g )
			{
				std::string msg;
				CCodeLib::UTF8ToGB2312( msg, ( *it_g ).c_str(), ( *it_g ).length() );
				m_pClient->OutputLogInfo( msg.c_str(), CQTalkLogConsole::TEXT_YELLOW );
			}

			rosterItem.jid         = ( *it ).second->jid();
			rosterItem.name        = ( *it ).second->name();
			rosterItem.subsciption = ( *it ).second->subscription();
			rosterItem.groups      = ( *it ).second->groups();
			rosterItem.presence	   = 6;
			m_pClient->m_rosterList.push_back( rosterItem );

	}

	AfxGetMainWnd()->PostMessage( \
						QTalkGlobal::WM_QTALK_MESSAGE, \
						QTalkGlobal::WM_QTALK_ROSTER, \
						QTalkGlobal::ROSTER_LIST_ALL );
}

// The rosters are not online or online
//  calling these method to implement roster update...

void CQTalkRosterListener::handleRosterPresence( const RosterItem& item,const std::string& resource,Presence presence, const std::string& msg )
{
	m_pClient->OutputLogInfo( "RosterListener::presenceUpdated", CQTalkLogConsole::TEXT_WHITE );
	QTalkGlobal::CIT_ROSTER_LIST cit = m_pClient->m_rosterList.begin();
	for(;cit != m_pClient->m_rosterList.end(); cit++)
	{
		if(cit->jid == item.jid())
		{
			cit->presence = presence;
		}
	}

	AfxGetMainWnd()->SendMessage( \
						QTalkGlobal::WM_QTALK_MESSAGE, \
						QTalkGlobal::WM_QTALK_ROSTER, \
						QTalkGlobal::ROSTER_PRESENCEUPDATE );
}

bool CQTalkRosterListener::handleSubscriptionRequest( const JID& jid, const std::string& msg )
{
	m_pClient->OutputLogInfo( "RosterListener::subscriptionRequest", CQTalkLogConsole::TEXT_WHITE );
//	m_pClient->m_cf = FALSE;
	if(!m_pClient->m_cf)
	{
		AfxGetMainWnd()->SendMessage( \
						QTalkGlobal::WM_QTALK_MESSAGE, \
						QTalkGlobal::WM_QTALK_ROSTER, \
						QTalkGlobal::ROSTER_SUBSCRIPTIONREQUEST);
	}

	if(!m_pClient->m_choice)
	{
		m_pClient->GetClient()->rosterManager()->unsubscribe(jid);
	}

	m_pClient->m_cf = FALSE;

	return true;
}

bool CQTalkRosterListener::handleUnsubscriptionRequest( const JID& jid, const std::string& msg )
{
	m_pClient->OutputLogInfo( "RosterListener::unsubscriptionRequest", CQTalkLogConsole::TEXT_WHITE );
	return true;
}

void CQTalkRosterListener::handleRosterError( Stanza* stanza )
{

}

void CQTalkRosterListener::handleNonrosterPresence( Stanza* stanza )
{

}

void CQTalkRosterListener::handleSelfPresence( const RosterItem& item, const std::string& resource,Presence presence, const std::string& msg )
{

}

聊天室:

#include "./src/client.h"
#include "./src/connectionlistener.h"
#include "./src/mucroomhandler.h"
#include "./src/mucroom.h"
#include "./src/disco.h"
#include "./src/stanza.h"
#include "./src/dataform.h"
#include "./src/gloox.h"
#include "./src/lastactivity.h"
#include "./src/loghandler.h"
#include "./src/logsink.h"
#include "./src/mucinvitationhandler.h"

using namespace gloox;

#include <stdio.h>
#include <locale.h>
#include <string>

#ifdef WIN32
#include <windows.h>
#endif

class CQTalkClient;

class QTalkMucRoom : public MUCRoomHandler,public gloox::MUCInvitationHandler
{
public:
	QTalkMucRoom();
	QTalkMucRoom( CQTalkClient* pClient);
	~QTalkMucRoom();
public:
	void start(CString roomName);
	void ToRoom(CString str,CString msg);
	void OnChatSession( std::string nick, std::string message );
	void SendToRoom(CString message);
	void ServerRoom();

private:
	virtual void handleMUCParticipantPresence( MUCRoom * /*room*/, const MUCRoomParticipant participant,
                                            Presence presence );
	virtual void handleMUCMessage( MUCRoom* /*room*/, const std::string& nick, const std::string& message,
                                   bool history, const std::string& /*when*/, bool priv );
	virtual void handleMUCSubject( MUCRoom * /*room*/, const std::string& nick, const std::string& subject );
	virtual void handleMUCError( MUCRoom * /*room*/, StanzaError error );
	virtual void handleMUCInfo( MUCRoom * /*room*/, int features, const std::string& name,
                                    const DataForm *infoForm );
	virtual void handleMUCItems( MUCRoom * /*room*/, const StringMap& items );
	virtual void handleMUCInviteDecline( MUCRoom * /*room*/, const JID& invitee, const std::string& reason );
	virtual bool handleMUCRoomCreation( MUCRoom *room );
	virtual void handleMUCInvitation( const JID& room, const JID& invitee, const std::string& reason,
                                        const std::string& body, const std::string& password,
                                        bool cont );
private:
    MUCRoom *m_room;
	MUCRoom *m_serverRoom;
	CQTalkClient* m_pClient;
	BOOL m_send;
	BOOL m_server;
};

#include "StdAfx.h"
#include "QTalkMucRoom.h"
#include "QTalkClient.h"

QTalkMucRoom::QTalkMucRoom()
{

//	m_pClient	 = NULL;
}

QTalkMucRoom::QTalkMucRoom(CQTalkClient* pClient)
{
	m_room		 = NULL;
	m_serverRoom = NULL;
	m_pClient	 = pClient;
	m_send		 = TRUE;
	m_server	 = TRUE;
}

QTalkMucRoom::~QTalkMucRoom()
{
	delete( m_room		);
	delete( m_serverRoom);
}

void QTalkMucRoom::start(CString roomName)
{
	const std::string strjid  = roomName.operator LPCTSTR();
	m_server = TRUE;

	JID nick(strjid);
	m_room = new MUCRoom( m_pClient->GetClient(), nick, this, 0 );
	m_room->join();
	m_room->getRoomInfo();
	m_room->getRoomItems();
//	delete(m_room);
}

void QTalkMucRoom::ServerRoom()
{
	m_server = FALSE;
	JID nick("conference.upower-a448cf28");
	m_serverRoom = new MUCRoom( m_pClient->GetClient(), nick, this, 0);
	m_serverRoom->getRoomItems();
//	delete( m_room );
}

void QTalkMucRoom::ToRoom(CString str,CString msg)
{
	const std::string strjid = str.operator LPCTSTR();
	JID jid(strjid);

	m_room->invite(jid,msg.operator LPCTSTR());
}

void QTalkMucRoom::SendToRoom(CString message)
{
	m_send = FALSE;
	const std::string strMessage = message.operator LPCTSTR();
	m_room->send(strMessage);
}

void QTalkMucRoom::handleMUCParticipantPresence( MUCRoom * /*room*/, const MUCRoomParticipant participant,
	Presence presence )
{
	std::string str = m_pClient->GetJID();
	if( presence == PresenceAvailable )
	{
//		printf( "!!!!!!!!!!!!!!!! %s is in the room, too\n", participant.nick->resource().c_str() );
		if(str.compare(participant.jid->bare()))
		{
			AfxGetMainWnd()->PostMessage( \
							QTalkGlobal::WM_QTALK_CONNECT, \
							QTalkGlobal::CONECT_PRESENCE_AVAILABLE, \
							NULL);
		}
	}
		
	else if( presence == PresenceUnavailable )
		printf( "!!!!!!!!!!!!!!!! %s left the room\n", participant.nick->resource().c_str() );
	else
		printf( "Presence is %d of %s\n", presence, participant.nick->resource().c_str() );
}

void QTalkMucRoom::handleMUCMessage( MUCRoom* /*room*/, const std::string& nick, const std::string& message,
	bool history, const std::string& /*when*/, bool priv )
{
	//printf( "%s said: '%s' (history: %s, private: %s)\n", nick.c_str(), message.c_str(),
	//	history ? "yes" : "no", priv ? "yes" : "no" );
	if(m_send)
	{
		OnChatSession(nick,message);
	}
	m_send = TRUE;
}

void QTalkMucRoom::handleMUCSubject( MUCRoom * /*room*/, const std::string& nick, const std::string& subject )
{
	if( nick.empty() )
		printf( "Subject: %s\n", subject.c_str() );
	else
		printf( "%s has set the subject to: '%s'\n", nick.c_str(), subject.c_str() );
}

void QTalkMucRoom::handleMUCError( MUCRoom * /*room*/, StanzaError error )
{
	printf( "!!!!!!!!got an error: %d", error );
}

void QTalkMucRoom::handleMUCInfo( MUCRoom * /*room*/, int features, const std::string& name,
	const DataForm *infoForm )
{
//	printf( "features: %d, name: %s, form xml: %s\n", features, name.c_str(), infoForm->tag()->xml().c_str() );
}

void QTalkMucRoom::handleMUCItems( MUCRoom * /*room*/, const StringMap& items )
{
	StringMap::const_iterator it = items.begin();
	for( ; it != items.end(); ++it )
	{
//		printf( "%s -- %s is an item here\n", (*it).first.c_str(), (*it).second.c_str() );
		m_pClient->m_serverRoomList.push_back((*it).first);
	}
	if(!m_server)
	{
		AfxGetMainWnd()->PostMessage( \
						QTalkGlobal::WM_QTALK_CHATROOM, \
						QTalkGlobal::WM_QTALK_SERVERCHATROOMLIST, \
						QTalkGlobal::SERVERCHATROOM_LIST);
	}
}

void QTalkMucRoom::handleMUCInviteDecline( MUCRoom * /*room*/, const JID& invitee, const std::string& reason )
{
	printf( "Invitee %s declined invitation. reason given: %s\n", invitee.full().c_str(), reason.c_str() );
}

bool QTalkMucRoom::handleMUCRoomCreation( MUCRoom *room )
{
	//     printf( "room %s didn't exist, beeing created.\n", room->name().c_str() );
	return true;
}


void QTalkMucRoom::handleMUCInvitation( const JID& room, const JID& invitee, const std::string& reason,
                                        const std::string& body, const std::string& password,
                                        bool cont )
{
//	int i = 0;
	const std::string strUsr = room.username();
	const std::string strInvitee = room.username();
	CString str = _T("");
	str.Format("%s@conference.upower-a448cf28/%s",strUsr.c_str(),strInvitee.c_str());
	JID nick(str.operator LPCTSTR());



	MUCRoom* m_serverRoom1 = new MUCRoom( m_pClient->GetClient(), nick, this, 0);
	m_room->join();
//	m_room = new MUCRoom( m_pClient->GetClient(), room, this, 0);
	//m_room->join();
	//JID jid("test@upower-a448cf28");
	//m_pClient->GetClient()->registerPresenceHandler(jid,this);
}

void QTalkMucRoom::OnChatSession( std::string nick, std::string message )
{
	m_pClient->m_nick = nick;
	m_pClient->m_rMessage = message;
	AfxGetMainWnd()->SendMessage(\
		QTalkGlobal::WM_QTALK_CHATROOM, \
		QTalkGlobal::WM_QTALK_ROOMSESSION, \
		QTalkGlobal::CHATROOM_MSG
		);
}

我这里是补充了QTalk中没有实现的一些小功能,希望能够帮助有这些需求的人,关于QTalk的视频部分我也做了修改能正常视频,内容太多,这里就不贴出来了,有需要的可联系我。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dylan55_you

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值