注册Jabber用户
static BOOL CALLBACK JabberRegisterDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
ThreadData *thread, *regInfo;
switch ( msg ) {
case WM_INITDIALOG:
{
TranslateDialogDefault( hwndDlg );
regInfo = ( ThreadData* ) lParam;
TCHAR text[256];
mir_sntprintf( text, SIZEOF(text), STR_FORMAT, TranslateT( "Register" ), regInfo->username, regInfo->server, regInfo->port );
SetDlgItemText( hwndDlg, IDC_REG_STATUS, text );
SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG )regInfo );
return TRUE;
}
case WM_COMMAND:
switch ( LOWORD( wParam )) {
case IDOK:
ShowWindow( GetDlgItem( hwndDlg, IDOK ), SW_HIDE );
ShowWindow( GetDlgItem( hwndDlg, IDCANCEL ), SW_HIDE );
ShowWindow( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ), SW_SHOW );
ShowWindow( GetDlgItem( hwndDlg, IDCANCEL2 ), SW_SHOW );
regInfo = ( ThreadData* ) GetWindowLong( hwndDlg, GWL_USERDATA );
thread = new ThreadData( JABBER_SESSION_REGISTER );
_tcsncpy( thread->username, regInfo->username, SIZEOF( thread->username ));
strncpy( thread->password, regInfo->password, SIZEOF( thread->password ));
strncpy( thread->server, regInfo->server, SIZEOF( thread->server ));
strncpy( thread->manualHost, regInfo->manualHost, SIZEOF( thread->manualHost ));
thread->port = regInfo->port;
thread->useSSL = regInfo->useSSL;
thread->reg_hwndDlg = hwndDlg;
mir_forkthread(( pThreadFunc )JabberServerThread, thread );
return TRUE;
case IDCANCEL:
case IDOK2:
EndDialog( hwndDlg, 0 );
return TRUE;
}
break;
case WM_JABBER_REGDLG_UPDATE: // wParam=progress ( 0-100 ), lparam=status string
if (( TCHAR* )lParam == NULL )
SetDlgItemText( hwndDlg, IDC_REG_STATUS, TranslateT( "No message" ));
else
SetDlgItemText( hwndDlg, IDC_REG_STATUS, ( TCHAR* )lParam );
if ( wParam >= 0 )
SendMessage( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ), PBM_SETPOS, wParam, 0 );
if ( wParam >= 100 ) {
ShowWindow( GetDlgItem( hwndDlg, IDCANCEL2 ), SW_HIDE );
ShowWindow( GetDlgItem( hwndDlg, IDOK2 ), SW_SHOW );
}
else SetFocus( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ));
return TRUE;
}
return FALSE;
}
登录Jabber
JabberServerThread
都在线程JabberServerThread里, 在程序里加了注释, 仔细分析代码吧:
void __cdecl JabberServerThread( ThreadData* info )
{
DBVARIANT dbv;
char* buffer;
int datalen;
int oldStatus;
PVOID ssl;
JabberLog( "Thread started: type=%d", info->type );
info->resolveID = -1;
info->auth = NULL;
if ( info->type == JABBER_SESSION_NORMAL )
{
// Normal server connection, we will fetch all connection parameters
// e.g. username, password, etc. from the database.
if ( jabberThreadInfo != NULL )
{
// Will not start another connection thread if a thread is already running.
// Make APC call to the main thread. This will immediately wake the thread up
// in case it is asleep in the reconnect loop so that it will immediately
// reconnect.
QueueUserAPC( JabberDummyApcFunc, jabberThreadInfo->hThread, 0 );
JabberLog( "Thread ended, another normal thread is running" );
//zhangcong//mir_free( info );
delete info; info = NULL; //zhangcong
return;
}
jabberThreadInfo = info;
if ( streamId )
mir_free( streamId );
streamId = NULL;
//读取登录帐号
if ( !JGetStringT( NULL, "LoginName", &dbv )) {
_tcsncpy( info->username, dbv.ptszVal, SIZEOF( info->username )-1 );
JFreeVariant( &dbv );
}
else {
JabberLog( "Thread ended, login name is not configured" );
JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
LBL_FatalError:
jabberThreadInfo = NULL;
oldStatus = jabberStatus;
jabberStatus = ID_STATUS_OFFLINE;
JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
LBL_Exit:
//zhangcong//mir_free( info );
delete info; info = NULL; //zhangcong
return;
}
if ( *rtrim(info->username) == '/0' ) {
JabberLog( "Thread ended, login name is not configured" );
JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
goto LBL_FatalError;
}
//读取jabber server地址
if ( !DBGetContactSetting( NULL, jabberProtoName, "LoginServer", &dbv )) {
strncpy( info->server, dbv.pszVal, SIZEOF( info->server )-1 );
JFreeVariant( &dbv );
}
else {
JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
JabberLog( "Thread ended, login server is not configured" );
goto LBL_FatalError;
}
//读取资源 (在注册用户时指定的)
if ( !JGetStringT( NULL, "Resource", &dbv )) {
_tcsncpy( info->resource, dbv.ptszVal, SIZEOF( info->resource )-1 );
JFreeVariant( &dbv );
}
else
{
_tcscpy( info->resource, _T("Miranda"));
}
//构造出完整的Jabber ID
TCHAR jidStr[128];
mir_sntprintf( jidStr, SIZEOF( jidStr ), _T("%s@") _T(TCHAR_STR_PARAM) _T("/%s"), info->username, info->server, info->resource );
_tcsncpy( info->fullJID, jidStr, SIZEOF( info->fullJID )-1 );
//读取登录密码, 如果已经保存的话
if ( JGetByte( "SavePassword", TRUE ) == FALSE )
{
mir_sntprintf( jidStr, SIZEOF( jidStr ), _T("%s@") _T(TCHAR_STR_PARAM), info->username, info->server );
// Ugly hack: continue logging on only the return value is &( onlinePassword[0] )
// because if WM_QUIT while dialog box is still visible, p is returned with some
// exit code which may not be NULL.
// Should be better with modeless.
onlinePassword[0] = ( char )-1;
hEventPasswdDlg = CreateEvent( NULL, FALSE, FALSE, NULL );
QueueUserAPC( JabberPasswordCreateDialogApcProc, hMainThread, ( DWORD )jidStr );
WaitForSingleObject( hEventPasswdDlg, INFINITE );
CloseHandle( hEventPasswdDlg );
if ( onlinePassword[0] == ( TCHAR ) -1 ) {
JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
JabberLog( "Thread ended, password request dialog was canceled" );
goto LBL_FatalError;
}
strncpy( info->password, onlinePassword, SIZEOF( info->password ));
info->password[ SIZEOF( info->password )-1] = '/0';
}
else {
if ( DBGetContactSetting( NULL, jabberProtoName, "Password", &dbv )) {
JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
JabberLog( "Thread ended, password is not configured" );
goto LBL_FatalError;
}
JCallService( MS_DB_CRYPT_DECODESTRING, strlen( dbv.pszVal )+1, ( LPARAM )dbv.pszVal );
strncpy( info->password, dbv.pszVal, SIZEOF( info->password ));
info->password[SIZEOF( info->password )-1] = '/0';
JFreeVariant( &dbv );
}
//读取jabber server端口, 如果指定了Jabber server地址的话, 读取指定的地址
if ( JGetByte( "ManualConnect", FALSE ) == TRUE ) {
if ( !DBGetContactSetting( NULL, jabberProtoName, "ManualHost", &dbv )) {
strncpy( info->manualHost, dbv.pszVal, SIZEOF( info->manualHost ));
info->manualHost[sizeof( info->manualHost )-1] = '/0';
JFreeVariant( &dbv );
}
info->port = JGetWord( NULL, "ManualPort", JABBER_DEFAULT_PORT );
}
else
{
info->port = JGetWord( NULL, "Port", JABBER_DEFAULT_PORT );
}
//是否使用SSL
info->useSSL = JGetByte( "UseSSL", FALSE );
}
else if ( info->type == JABBER_SESSION_REGISTER ) //注册新用户连接
{
// Register new user connection, all connection parameters are already filled-in.
// Multiple thread allowed, although not possible : )
// thinking again.. multiple thread should not be allowed
info->reg_done = FALSE;
SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 25, ( LPARAM )TranslateT( "Connecting..." ));
iqIdRegGetReg = -1;
iqIdRegSetReg = -1;
}
else
{
JabberLog( "Thread ended, invalid session type" );
goto LBL_Exit;
}
char connectHost[128];
if ( info->manualHost[0] == 0 ) {
int port_temp;
strncpy( connectHost, info->server, SIZEOF(info->server));
if ( port_temp = xmpp_client_query( connectHost )) { // port_temp will be > 0 if resolution is successful
JabberLog("%s%s resolved to %s:%d","_xmpp-client._tcp.",info->server,connectHost,port_temp);
if (info->port==0 || info->port==5222)
info->port = port_temp;
}
else JabberLog("%s%s not resolved", "_xmpp-client._tcp.", connectHost);
}
else
{
strncpy( connectHost, info->manualHost, SIZEOF(connectHost)); // do not resolve if manual host is selected
}
JabberLog( "Thread type=%d server='%s' port='%d'", info->type, connectHost, info->port );
int jabberNetworkBufferSize = 2048;
if (( buffer=( char* )mir_alloc( jabberNetworkBufferSize+1 )) == NULL ) { // +1 is for '/0' when debug logging this buffer
JabberLog( "Cannot allocate network buffer, thread ended" );
if ( info->type == JABBER_SESSION_NORMAL ) {
oldStatus = jabberStatus;
jabberStatus = ID_STATUS_OFFLINE;
JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
jabberThreadInfo = NULL;
}
else if ( info->type == JABBER_SESSION_REGISTER ) {
SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Not enough memory" ));
}
JabberLog( "Thread ended, network buffer cannot be allocated" );
goto LBL_Exit;
}
//与Jabber server建立socket连接
info->s = JabberWsConnect( connectHost, info->port );
if ( info->s == NULL )
{
JabberLog( "Connection failed ( %d )", WSAGetLastError());
if ( info->type == JABBER_SESSION_NORMAL )
{
if ( jabberThreadInfo == info )
{
oldStatus = jabberStatus;
jabberStatus = ID_STATUS_OFFLINE;
JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
jabberThreadInfo = NULL;
}
}
else if ( info->type == JABBER_SESSION_REGISTER )
{
SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Cannot connect to the server" ));
}
JabberLog( "Thread ended, connection failed" );
mir_free( buffer );
goto LBL_Exit;
}
// Determine local IP
int socket = JCallService( MS_NETLIB_GETSOCKET, ( WPARAM ) info->s, 0 );
if ( info->type==JABBER_SESSION_NORMAL && socket!=INVALID_SOCKET ) {
struct sockaddr_in saddr;
int len;
len = sizeof( saddr );
getsockname( socket, ( struct sockaddr * ) &saddr, &len );
jabberLocalIP = saddr.sin_addr.S_un.S_addr;
JabberLog( "Local IP = %s", inet_ntoa( saddr.sin_addr ));
}
if ( info->useSSL )
{
JabberLog( "Intializing SSL connection" );
if ( JabberSslInit() && socket != INVALID_SOCKET )
{
JabberLog( "SSL using socket = %d", socket );
if (( ssl=pfn_SSL_new( jabberSslCtx )) != NULL )
{
JabberLog( "SSL create context ok" );
if ( pfn_SSL_set_fd( ssl, socket ) > 0 )
{
JabberLog( "SSL set fd ok" );
if ( pfn_SSL_connect( ssl ) > 0 )
{
JabberLog( "SSL negotiation ok" );
info->ssl = ssl; // This make all communication on this handle use SSL
JabberLog( "SSL enabled for handle = %d", info->s );
}
else
{
JabberLog( "SSL negotiation failed" );
pfn_SSL_free( ssl );
}
}
else
{
JabberLog( "SSL set fd failed" );
pfn_SSL_free( ssl );
}
}
}
if ( !info->ssl )
{
if ( info->type == JABBER_SESSION_NORMAL )
{
oldStatus = jabberStatus;
jabberStatus = ID_STATUS_OFFLINE;
JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
if ( jabberThreadInfo == info )
jabberThreadInfo = NULL;
}
else if ( info->type == JABBER_SESSION_REGISTER )
{
SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Cannot connect to the server" ));
}
mir_free( buffer );
if ( !hLibSSL )
MessageBox( NULL, TranslateT( "The connection requires an OpenSSL library, which is not installed." ), TranslateT( "Jabber Connection Error" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
JabberLog( "Thread ended, SSL connection failed" );
goto LBL_Exit;
}
}
// User may change status to OFFLINE while we are connecting above
if ( jabberDesiredStatus != ID_STATUS_OFFLINE || info->type == JABBER_SESSION_REGISTER )
{
if ( info->type == JABBER_SESSION_NORMAL )
{
jabberConnected = TRUE;
int len = _tcslen( info->username ) + strlen( info->server )+1;
jabberJID = ( TCHAR* )mir_alloc( sizeof( TCHAR)*( len+1 ));
mir_sntprintf( jabberJID, len+1, _T("%s@") _T(TCHAR_STR_PARAM), info->username, info->server );
if ( JGetByte( "KeepAlive", 1 ))
jabberSendKeepAlive = TRUE;
else
jabberSendKeepAlive = FALSE;
//连接建立以后创建一个保持活跃的线程
mir_forkthread(( pThreadFunc )JabberKeepAliveThread, info );
}
xmlStreamInitializeNow( info );
JabberLog( "Entering main recv loop" );
datalen = 0;
//zhangcong//main recv loop, 出现异常时,将break loop
for ( ;; )
{
int recvResult = info->recv( buffer+datalen, jabberNetworkBufferSize-datalen);
int bytesParsed;
JabberLog( "recvResult = %d", recvResult );
if ( recvResult <= 0 )
break;
datalen += recvResult;
buffer[datalen] = '/0';
if ( info->ssl && DBGetContactSettingByte( NULL, "Netlib", "DumpRecv", TRUE ) == TRUE )
{
// Emulate netlib log feature for SSL connection
char* szLogBuffer = ( char* )mir_alloc( recvResult+128 );
if ( szLogBuffer != NULL )
{
strcpy( szLogBuffer, "( SSL ) Data received/n" );
memcpy( szLogBuffer+strlen( szLogBuffer ), buffer+datalen-recvResult, recvResult+1 /* also copy /0 */ );
Netlib_Logf( hNetlibUser, "%s", szLogBuffer ); // %s to protect against when fmt tokens are in szLogBuffer causing crash
mir_free( szLogBuffer );
}
}
//XmlParse接收到的数据
bytesParsed = JabberXmlParse( &xmlState, buffer );
JabberLog( "bytesParsed = %d", bytesParsed );
if ( bytesParsed > 0 )
{
if ( bytesParsed < datalen )
memmove( buffer, buffer+bytesParsed, datalen-bytesParsed );
datalen -= bytesParsed;
}
else if ( datalen == jabberNetworkBufferSize )
{
//如果缓冲区已满, 扩充缓冲区
jabberNetworkBufferSize += 65536;
JabberLog( "Increasing network buffer size to %d", jabberNetworkBufferSize );
if (( buffer=( char* )mir_realloc( buffer, jabberNetworkBufferSize+1 )) == NULL ) {
JabberLog( "Cannot reallocate more network buffer, go offline now" );
break;
}
}
else
{
JabberLog( "Unknown state: bytesParsed=%d, datalen=%d, jabberNetworkBufferSize=%d", bytesParsed, datalen, jabberNetworkBufferSize );
}
if (xmlStreamToBeInitialized)
xmlStreamInitializeNow(info);
}
//出现异常后, 跳出main recv loop, 清理现场,设置状态
JabberXmlDestroyState(&xmlState);
if ( info->type == JABBER_SESSION_NORMAL )
{
jabberOnline = FALSE;
jabberConnected = FALSE;
JabberEnableMenuItems( FALSE );
if ( hwndJabberChangePassword )
{
//DestroyWindow( hwndJabberChangePassword );
// Since this is a different thread, simulate the click on the cancel button instead
SendMessage( hwndJabberChangePassword, WM_COMMAND, MAKEWORD( IDCANCEL, 0 ), 0 );
}
if ( jabberChatDllPresent )
QueueUserAPC( JabberOfflineChatWindows, hMainThread, 0 );
JabberListRemoveList( LIST_CHATROOM );
if ( hwndJabberAgents )
SendMessage( hwndJabberAgents, WM_JABBER_CHECK_ONLINE, 0, 0 );
if ( hwndJabberGroupchat )
SendMessage( hwndJabberGroupchat, WM_JABBER_CHECK_ONLINE, 0, 0 );
if ( hwndJabberJoinGroupchat )
SendMessage( hwndJabberJoinGroupchat, WM_JABBER_CHECK_ONLINE, 0, 0 );
// Set status to offline
oldStatus = jabberStatus;
jabberStatus = ID_STATUS_OFFLINE;
JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
// Set all contacts to offline
HANDLE hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
while ( hContact != NULL )
{
if ( !lstrcmpA(( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ), jabberProtoName ))
if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE )
JSetWord( hContact, "Status", ID_STATUS_OFFLINE );
hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
}
mir_free( jabberJID );
jabberJID = NULL;
jabberLoggedInTime = 0;
JabberListWipe();
if ( hwndJabberAgents )
{
SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )"" );
SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
}
if ( hwndJabberVcard )
SendMessage( hwndJabberVcard, WM_JABBER_CHECK_ONLINE, 0, 0 );
}
else if ( info->type==JABBER_SESSION_REGISTER && !info->reg_done )
{
SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Connection lost" ));
}
}
else if ( info->type == JABBER_SESSION_NORMAL )
{
oldStatus = jabberStatus;
jabberStatus = ID_STATUS_OFFLINE;
JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
}
JabberLog( "Thread ended: type=%d server='%s'", info->type, info->server );
if ( info->type==JABBER_SESSION_NORMAL && jabberThreadInfo==info )
{
if ( streamId ) mir_free( streamId );
streamId = NULL;
jabberThreadInfo = NULL;
}
mir_free( buffer );
JabberLog( "Exiting ServerThread" );
goto LBL_Exit;
}
JabberRecvMessage
int JabberRecvMessage( WPARAM wParam, LPARAM lParam )
{
CCSDATA *ccs = ( CCSDATA* )lParam;
PROTORECVEVENT *pre = ( PROTORECVEVENT* )ccs->lParam;
DBEVENTINFO dbei = { 0 };
dbei.cbSize = sizeof( dbei );
dbei.szModule = jabberProtoName;
dbei.timestamp = pre->timestamp;
dbei.flags = pre->flags&PREF_CREATEREAD?DBEF_READ:0;
dbei.eventType = EVENTTYPE_MESSAGE;
dbei.cbBlob = strlen( pre->szMessage ) + 1;
if ( pre->flags & PREF_UNICODE )
dbei.cbBlob *= ( sizeof( wchar_t )+1 );
dbei.pBlob = ( PBYTE ) pre->szMessage;
JCallService( MS_DB_EVENT_ADD, ( WPARAM ) ccs->hContact, ( LPARAM )&dbei );
return 0;
}