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
);
}