六、2008年3月7日
作者:青青子衿
email:[email protected]
1、 CString類,Bot定義了自己的字符串類,與其他字符串類相比,它增加了加密字符串的功能,具體分析如下:
5個成員變量:
bool m_bIsCryptStr ; //字符串是否加密
int m_iCryptKey ; //用於加密的key的值
char * m_szString ; //保存字符串的指針
c har * m_szTemp ; //字符串臨時指針
int m_iLength ; //字符串的長度
39個成員函數:
public :
CString (); //構造函數
CString ( const char * szString );
CString ( const CString & pString );
CString ( const int iValue );
virtual ~ CString (); //析構函數
void Assign ( const char * szString ); //字符串填充函數
void Assign ( const CString & pString );
void Assign ( const int iValue );
void Append ( const char * szString ); //字符串追加寒函數
void Append ( const CString & pString );
void Append ( const int iValue );
int Compare ( const char * szString ) const ; //字符串比較函數
int Compare ( const CString & pString ) const ;
int CompareNoCase ( const char * szString ) const ; //忽略大小寫的字符串比較函數
int CompareNoCase ( const CString & pString ) const ;
CString Decrypt () const ; //字符串加密函數
void Empty (); //字符串清空函數
int Find ( const char cChar ) const ; //字符查找函數
int Find ( const char cChar , int iStart ) const ;
int Find ( const CString & pString ) const ; //字符串查找函數
int Find ( const CString & pString , int iStart ) const ;
int Find ( const char * szString ) const ;
int Find ( const char * szString , int iStart ) const ;
void Format ( const char * szFormat , ...); //字符串的格式化輸入函數
char * GetBuffer ( int iBufLen ); //字符串獲得緩衝區的函數
int GetLength () const ; //獲得字符串長度的函數
CString Mid ( int iFirst , int iCount ) const ; //截取子字符串的函數
CString Mid ( int iFirst ) const ;
CString Token ( int iNum , const char * szDelim , bool bUseQuotes ); //以特定分隔符,分割提取子字符串的函數
CString Token ( int iNum , const char * szDelim );
void operator =( const CString & sStr ); //重載賦值運算符函數
void operator =( const char * szStr );
char & operator []( int iPos ); //重載[]運算符函數
const char & operator []( int iPos ) const ;
operator const char *() const //重載*()運算符
{
return m_szString ;
}
operator char *()
{
return m_szString ;
}
const char * CStr () const ; //獲取字符串變量中,字符串緩衝區指針的函數
const char * CStr ();
char * Str ();
這裏着重分析一下 Token 函數
//////////////////////////////////////////////////////////////////////////
//
//函數功能:按照分隔符將字符串分爲若干段,
//參數: int iNum 返回第一段符合要求的字符串
// const char *szDelim 分割字符
// bool bUseQuotes 是否支持轉義字符
//返回值: CString 如果找到返回相應的子字符串,否則返回NULL字符串
//
/////////////////////////////////////////////////////////////////////////
CString CString :: Token ( int iNum , const char * szDelim , bool bUseQuotes )
{
if ( m_bIsCryptStr )
{
return Decrypt (). Token ( iNum , szDelim , bUseQuotes );
}
std :: vector < char *> vTokens ; //注意這裏是一個字符指針數組類型
CString sTemp ( m_szString );
char * szText = sTemp . Str ();
bool bInQuotes = false ;
while (* szText )
{
while (* szText == szDelim [0])
{
//尋找字符串中的分割字符,找到後跳出循環
szText ++; // skip leading whitespace
}
//如果分割符爲“"”雙引號,bInQuotes賦值爲true
bInQuotes =(* szText == '/"' ); // see if this token is quoted
//如果bInQuotes爲ture
if ( bInQuotes )
{
szText ++; // skip leading quote
}
vTokens . push_back ( szText ); // store position of current token
if ( bInQuotes )
{ // find next quote followed by a space or terminator
while (* szText &&! (* szText == '/"' && ( szText [1]== ' ' || szText [1]== '/0' ) ) )
{
szText ++;
}
if (* szText )
{
* szText = '/0' ;
if ( szText [1]) { szText +=2};
}
}
else // !bInQuotes
{
// skip to next non-whitespace/delimiter character
while (* szText &&* szText != szDelim [0]) //字符串沒有結束,當前字符不是分割富
{
szText ++;
}
if (* szText &&* szText == szDelim [0]) //字符串沒有結束,當前字符是分割富
{
* szText = '/0' ; //該字符賦值爲0,及結束符
szText ++;
}
} // if(bInQuotes)
} // while(*szText)
if ( iNum >= vTokens . size ())
{
return CString ( "" );
}
return CString ( vTokens . at ( iNum ));
}
2、 CMessage 類的分析
該類沒有成員函數數,只有幾個成員變量
class CMessage
{
public :
CString sChatString ; //聊天字符串
CString sSrc ; //源
CString sDest ; //目的
CString sHost ; //主機
CString sIdentd ; //ID號
CString sReplyTo ; //回覆(答覆)
CString sCmd ; //命令
bool bSilent ; //靜默?
bool bNotice ; //通告??
};
3、 CCmdExecutor 類的分析
class CCmdExecutor : public CThread
{
public :
CCmdExecutor () //構造函數
{
m_pMsg = NULL ;
m_bMsgSet = false ;
}
virtual ~ CCmdExecutor () { } //析構函數
virtual void * Run ();
CMessage * Get () //獲得消息類對象指針
{
return m_pMsg ;
}
void Set ( CMessage *); //設置消息類對象
private :
CMessage * m_pMsg ;
CMessage m_mMsg ; //消息類變量
bool m_bMsgSet ;
};
(1)、 : Run () 函數
/////////////////////////////////////////////////////////////
//
//函數功能:繼承線程類的run函數
//
///////////////////////////////////////////////////////////////
void * CCmdExecutor :: Run ()
{
while (! m_bMsgSet ) //如果沒有消息設置,休息1秒鐘 ,再判斷
{
Sleep (1000);
}
g_cMainCtrl . m_cBot . Recv (& m_mMsg ); //接收消息
g_cMainCtrl . m_lCanJoin . push_back ( this ); //將消息對象放到線程列表中,因爲消息類繼承了線程類
return NULL ;
}
(2)、 Set ( CMessage * pMsg ) 函數
////////////////////////////////////////////////////////////////////
//
//函數功能:設置消息
//參數: CMessage *pMsg 消息類對象指針
//返回值:void
//
//////////////////////////////////////////////////////////////////////
void CCmdExecutor :: Set ( CMessage * pMsg )
{
m_pMsg = pMsg ; //將消息類對象指針賦值給成員變量
m_mMsg . bNotice = m_pMsg -> bNotice ;
m_mMsg . bSilent = m_pMsg -> bSilent ;
m_mMsg . sSrc . Assign ( m_pMsg -> sSrc ); //賦值消息源
m_mMsg . sIdentd . Assign ( m_pMsg -> sIdentd ); //賦值ID
m_mMsg . sHost . Assign ( m_pMsg -> sHost ); //賦值主機名
m_mMsg . sDest . Assign ( m_pMsg -> sDest ); //賦值目的地
m_mMsg . sChatString . Assign ( m_pMsg -> sChatString ); //賦值聊天字符串
m_bMsgSet = true ; //將m_bMsgSet設爲true,使run函數啓動。
}
3、 CIRC :: Run () CIRC類的run函數
void * CIRC :: Run ()
{
while ( m_bRunning && g_cMainCtrl . m_bRunning )
{
//CIRC類的成員變量中的m_bRunning變量爲true,並且全局變量CMainCtrl類型的g_cMainCtrl變量的
//m_bRunning成員變量也爲true。則運行循環中的代碼
//如果連接失敗,在這裏處理善後工作
if (( m_iServerNum ==0 && m_iFailCount >5) || ( m_iServerNum !=0 && m_iFailCount >2))
{
//如果連接的是0號服務器並且連接失敗次數大於5;或者連接的不是0號服務器,並且連接失敗次數大於2,執行if裏的代碼
// Reset CIRC values, disconnect the sockets, and clear the logins
m_bJoined = false ;
m_bConnected = false ;
if ( m_sSocket != INVALID_SOCKET )
{
xClose ( m_sSocket ); //通過宏定義調用closesocket,關閉套接字
}
m_sSocket = INVALID_SOCKET ;
g_cMainCtrl . m_cMac . ClearLogins (); //清除相關Login登錄信息
#ifdef DBGCONSOLE //輸出登錄失敗的相關日誌
if (! m_iServerNum ) // If its the root server, use another text
{
g_cMainCtrl . m_cConsDbg . Log (1, "CIRC(0x%8.8Xh): Giving up root server /"%s:%d/" after %d retries!/n" , this , g_cMainCtrl . m_cBot . si_server . sValue . CStr (), g_cMainCtrl . m_cBot . si_port . iValue , m_iFailCount );
}
else
{
g_cMainCtrl . m_cConsDbg . Log (2, "CIRC(0x%8.8Xh): Giving up server /"%s:%d/" after %d retries!/n" , this , g_cMainCtrl . m_cBot . si_server . sValue . CStr (), g_cMainCtrl . m_cBot . si_port . iValue , m_iFailCount );
}
#endif // DBGCONSOLE
// Select new server
m_iServerNum ++; //選擇下一個服務器進行連接嘗試
if ( m_iServerNum > m_vServers . size ()-1) //當準備用於連接的服務器序號已經大於了實際存在的最高次序的服務器序號,將服務器的序號置0,
{ //重新重0號,root服務器開始做連接嘗試。
m_iServerNum =0;
}
// m_iServerNum=0; // Server switching disabled for now, remove this to enable
m_iFailCount =0; // Reset the failure count //將連接失敗計數器置0
//從服務器列表中,提取新的服務器信息,並將這些信息設置到g_cMainCtrl.m_cBot變量中去。
//Set the cvars to the new values
g_cMainCtrl . m_cCVar . SetCVar (& g_cMainCtrl . m_cBot . si_chanpass , m_vServers . at ( m_iServerNum )-> si_chanpass . sValue . m_szString );
g_cMainCtrl . m_cCVar . SetCVar (& g_cMainCtrl . m_cBot . si_mainchan , m_vServers . at ( m_iServerNum )-> si_mainchan . sValue . m_szString );
g_cMainCtrl . m_cCVar . SetCVar (& g_cMainCtrl . m_cBot . si_nickprefix , m_vServers . at ( m_iServerNum )-> si_nickprefix . sValue . m_szString );
g_cMainCtrl . m_cCVar . SetCVar (& g_cMainCtrl . m_cBot . si_port , m_vServers . at ( m_iServerNum )-> si_port . sValue . m_szString );
g_cMainCtrl . m_cCVar . SetCVar (& g_cMainCtrl . m_cBot . si_server , m_vServers . at ( m_iServerNum )-> si_server . sValue . m_szString );
g_cMainCtrl . m_cCVar . SetCVar (& g_cMainCtrl . m_cBot . si_servpass , m_vServers . at ( m_iServerNum )-> si_servpass . sValue . m_szString );
g_cMainCtrl . m_cCVar . SetCVar (& g_cMainCtrl . m_cBot . si_usessl , m_vServers . at ( m_iServerNum )-> si_usessl . sValue . m_szString );
m_lLastRecv = GetTickCount (); //獲得當前的時間值。
}
//if_1
if ( m_sSocket == INVALID_SOCKET ) //如果套接字無效,則創建一個TCP套接字
{
// We don't have a socket yet, try to create one
m_sSocket = socket ( AF_INET , SOCK_STREAM , IPPROTO_TCP ); //創建TCP套接字
m_bConnected = false ; //將連接狀態置爲false,未連接
Sleep (2000);
}
else if (! m_bConnected ) //if_1
{
//如果m_bConnected==false,還沒有連接IRC服務器,調用下面的代碼
// We're not connected yet, connect to the server
// Start IdentD
if (! g_cMainCtrl . m_bIdentD_Running && g_cMainCtrl . m_cBot .identd_enabled. bValue )
{
g_cMainCtrl . m_cIdentD . Start (); //★這裏待分析了CIdentD之後就清楚了
}
// Setup vars, resolve address
sockaddr_in ssin ;
int iErr ;
memset (& ssin , 0, sizeof ( ssin ));
ssin . sin_family = AF_INET ;
#ifdef DBGCONSOLE
g_cMainCtrl . m_cConsDbg . Log (4, "CIRC(0x%8.8Xh): Trying to connect to /"%s:%d/".../n" , this , g_cMainCtrl . m_cBot . si_server . sValue . CStr (), g_cMainCtrl . m_cBot . si_port . iValue );
#endif
ssin . sin_port = htons ( g_cMainCtrl . m_cBot . si_port . iValue ); //服務器端口
ssin . sin_addr . s_addr = ResolveAddress ( g_cMainCtrl . m_cBot . si_server . sValue . CStr ()); //服務器IP
#ifdef DBGCONSOLE
g_cMainCtrl . m_cConsDbg . Log (4, "CIRC(0x%8.8Xh): Resolved /"%s/" to /"%s/".../n" , this , g_cMainCtrl . m_cBot . si_server . sValue . CStr (), inet_ntoa ( to_in_addr ( ssin . sin_addr . s_addr )));
#endif
m_lLastRecv = GetTickCount (); //獲得當前的時間
// Try to connect to the server
iErr = connect ( m_sSocket , ( sockaddr *)& ssin , sizeof ( sockaddr_in )); //調用網絡連接函數
if ( iErr == SOCKET_ERROR ) //如果連接失敗
{
// Connect failed, exit
#ifdef DBGCONSOLE
g_cMainCtrl . m_cConsDbg . Log (4, "CIRC(0x%8.8Xh): Connection to /"%s:%d/" failed!/n" , this , g_cMainCtrl . m_cBot . si_server . sValue . CStr (), g_cMainCtrl . m_cBot . si_port . iValue );
#endif
Sleep (10000);
m_bConnected = false ; //連接的狀態設爲false
m_iFailCount ++; //失敗計數器加1
continue ; //繼續外邊的while循環
}
else //如果連接成功
{ // Connection established
#ifdef DBGCONSOLE
g_cMainCtrl . m_cConsDbg . Log (3, "CIRC(0x%8.8Xh): Connection to /"%s:%d/" established!/n" , this , g_cMainCtrl . m_cBot . si_server . sValue . CStr (), g_cMainCtrl . m_cBot . si_port . iValue );
#endif
m_bConnected = true ; //連接狀態設爲true
m_bJoined = false ; //是否加入頻道的設置設爲false
}
m_lLastRecv = GetTickCount (); //獲得當前的時間
if ( g_cMainCtrl . m_cBot . si_usessl . bValue ) //查看是否在CBot中設置了,使用ssl協議通訊
{
//以下過程用來創建SSL的通訊
#ifdef DBGCONSOLE
g_cMainCtrl . m_cConsDbg . Log (3, "CIRC(0x%8.8Xh): Starting SSL socket.../n" , this );
#endif
m_csslSocket . AttachToSocket ( m_sSocket ); //將套接字關聯到CSSLSocket上
#ifdef DBGCONSOLE
g_cMainCtrl . m_cConsDbg . Log (3, "CIRC(0x%8.8Xh): Doing SSL handshake.../n" , this );
#endif
if (! m_csslSocket . Connect ()) //進行SSL協議的連接
{
//如果連接失敗,做以下操作
xClose ( m_sSocket ); //關閉套接字
m_sSocket = INVALID_SOCKET ; //將套接字變量設爲INVALID_SOCKET
#ifdef DBGCONSOLE
g_cMainCtrl . m_cConsDbg . Log (3, "CIRC(0x%8.8Xh): SSL handshake failed.../n" , this );
#endif
Sleep (10000); //10秒
m_bConnected = false ; //將連接狀態設爲false
m_iFailCount ++; //連接失敗計數器加1
continue ; //繼續外邊的while循環
}
m_lLastRecv = GetTickCount (); //獲得當前的時間
}
// Get local ip address 獲得本地的IP
sockaddr sa ;
socklen_t sas = sizeof ( sa );
memset (& sa , 0, sizeof ( sa ));
getsockname ( m_sSocket , & sa , & sas );
char szTemp [64];
sprintf ( szTemp , "%d.%d.%d.%d" , ( unsigned char ) sa . sa_data [2], ( unsigned char ) sa . sa_data [3],
( unsigned char ) sa . sa_data [4], ( unsigned char ) sa . sa_data [5]);
m_sLocalIp . Assign ( szTemp );
m_lLocalAddr = inet_addr ( szTemp ); //將本地IP保存到該字符串變量中
//登錄服務器
// Send the server password
if ( g_cMainCtrl . m_cBot . si_servpass . sValue . Compare ( "" )) //如果服務器密碼不爲NULL
{
//發送密碼
SendRawFormat ( "PASS %s/r/n" , g_cMainCtrl . m_cBot . si_servpass . sValue . CStr ()); //★需要進一步分析
}
// Send the nick and register with the irc server
SendRawFormat ( "NICK %s/r/nUSER %s 0 0 :%s/r/n" , g_cMainCtrl . m_sUserName . CStr (), //發送用戶密碼
g_cMainCtrl . m_sUserName . CStr (), g_cMainCtrl . m_sUserName . CStr ());
}
else //if_1 //處理連接成功,之後的數據通訊過程
{
//下面的代碼主要處理數據接收工作
char szLine [8192];
memset ( szLine , 0, sizeof ( szLine ));
// Wait for a complete line to be received
bool bRecvd = false ;
if ( g_cMainCtrl . m_cBot . si_usessl . bValue )
{
//如果使用ssl協議通信,執行這裏的代碼
bRecvd = recv_line_irc ( m_sSocket , szLine , sizeof ( szLine ), & m_csslSocket );
}
else
{
//明文通訊由這裏來處理
bRecvd = recv_line_irc ( m_sSocket , szLine , sizeof ( szLine ), NULL );
}
if ( bRecvd ) //判斷是否接收成功
{
m_lLastRecv = GetTickCount (); //獲得當前的時間
CString sLine ( szLine );
#ifdef DBGCONSOLE
g_cMainCtrl . m_cConsDbg . Log (3, "CIRC(0x%8.8Xh): Received: /"%s/"/n" , this , sLine . CStr ());
#endif
// Set m_bJoined if we joined the channel
if (! sLine . Token (1, " " ). Compare ( "353" ) && ! sLine . Token (4, " " ). Compare ( g_cMainCtrl . m_cBot . si_mainchan . sValue ))
{
m_bJoined = true ; //如果 頻道信息與.m_cBot中所設置的相同,則進入頻道成功,將變量m_bJoined置爲false.
}
// Send PONG if we're PING'ed
else if (! sLine . Token (0, " " ). Compare ( "PING" )) //處理接收到的PING消息
{
SendRawFormat ( "PONG %s/r/n" , sLine . Token (1, " " ). CStr ()); //向服務器發送“PONG”消息
if (! m_bJoined ) //如果m_bJoined爲false,還沒有加入頻道,發送加入頻道的“JOIN”消息
{
SendRawFormat ( "JOIN %s %s/r/n" ,
g_cMainCtrl . m_cBot . si_mainchan . sValue . CStr (),
g_cMainCtrl . m_cBot . si_chanpass . sValue . CStr ());
}
}
//處理髮送來的NOTICE消息
else if (! sLine . Token (1, " " ). Compare ( "NOTICE" ))
{
if ( sLine . Token (18, " " ). Compare ( "" )) //第18段空格後,有子字符串
{
if (! sLine . Token (17, " " ). Compare ( "pong" )) //第17段空格後的字符串是pong
{
SendRawFormat ( "PONG %s/r/n" , sLine . Token (18, " " ). CStr ()); //將第18段字符串發送會服務端
}
if (! m_bJoined ) //如果還沒有加入頻道
{
//向服務器發送JOIN消息
SendRawFormat ( "JOIN %s %s/r/n" ,
g_cMainCtrl . m_cBot . si_mainchan . sValue . CStr (),
g_cMainCtrl . m_cBot . si_chanpass . sValue . CStr ());
}
}
}
// Connected to the server, get the hostname
//如果接收數據中的第一段的字符串是“001”或“005”
else if (! sLine . Token (1, " " ). Compare ( "001" ) || ! sLine . Token (1, " " ). Compare ( "005" ))
{
if (! m_bJoined ) //如果還未加入頻道,發送JOIN加入頻道
{
SendRawFormat ( "JOIN %s %s/r/n" ,
g_cMainCtrl . m_cBot . si_mainchan . sValue . CStr (),
g_cMainCtrl . m_cBot . si_chanpass . sValue . CStr ());
if ( g_cMainCtrl . m_bCanSpamAOL && g_cMainCtrl . m_cBot . spam_aol_enabled . bValue )
{
SendRawFormat ( "JOIN %s %s/r/n" ,
g_cMainCtrl . m_cBot .spam_aol_channel. sValue . CStr (), //★注意這個值的作用還不清楚
g_cMainCtrl . m_cBot . si_chanpass . sValue . CStr ());
}
}
SendRawFormat ( "USERHOST %s/r/n" , g_cMainCtrl . m_sUserName . CStr ()); //發送USERHOST消息
}
// Get the hostname
else if (! sLine . Token (1, " " ). Compare ( "302" )) //如果第一段的字符串是302 執行,獲取主機名的操作
{
CString sTemp = sLine . Token (3, " " ); //提取第三段的字符串
char * h = strstr ( sTemp . Str (), "@" ); //找到“@”後邊的子字符串
if ( h )
{
m_sLocalHost . Assign ( h +1); //將子字符串賦值給m_sLocalHost變量
}
}
// Its a private message
else if (! sLine . Token (1, " " ). Compare ( "PRIVMSG" )) //如果消息中的第一個字符串爲"PRIVMSG",說明該消息爲私有消息
{
CMessage * msg = new CMessage ; //這裏有必要先分析一下CMessage類型
CCmdExecutor * ex = new CCmdExecutor ;
// Check silent and notice parameters, and set bool flags accordingly
if ( strstr ( sLine . CStr (), " -s" )) //私有命令中" -s" 表示靜默
{
msg -> bSilent = true ;
}
else
{
msg -> bSilent = false ;
}
if ( strstr ( sLine . CStr (), " -n" )) //私有命令中" " -n"" 表示通告
{
msg -> bNotice = true ;
}
else
{
msg -> bNotice = false ;
}
//分解命令,將其放入CMsg類的對象中。
// Parse the strings, and insert them into the message
msg -> sSrc . Assign ( sLine . Token (0, ":" ). Token (0, " " ). Token (0, "!" ));
msg -> sIdentd . Assign ( sLine . Token (1, "!" ). Token (0, "@" ));
msg -> sHost . Assign ( sLine . Token (1, "@" ). Token (0, " " ));
msg -> sDest . Assign ( sLine . Token (2, " " ));
char * szText = strstr ( sLine . Str (), " :" );
if ( szText )
{
msg -> sChatString . Assign ( szText +2);
}
else
{
msg -> sChatString . Assign ( "" );
}
#ifdef DBGCONSOLE
g_cMainCtrl . m_cConsDbg . Log (1, "CIRC(0x%8.8Xh): %s / %s / %s / %s / /"%s/".../n" , /
this , msg -> sSrc . CStr (), msg -> sIdentd . CStr (), msg -> sHost . CStr (), /
msg -> sDest . CStr (), msg -> sChatString . CStr ());
#endif
// Let the bot handle it
ex -> Start (); //啓動線程,個人認爲並沒有運行
ex -> Set ( msg ); //所有私有消息應該都在新線程中處理
delete msg ;
}
// Someone got kicked, maybe the bot itself
//處理KICK命令
else if (! sLine . Token (1, " " ). Compare ( "KICK" ))
{
// If someone is logged in by that name, log him out
login * pLogin = g_cMainCtrl . m_cMac . FindLogin ( sLine . Token (3, " " )); //第三個字符串是登錄名稱
if ( pLogin ) //如果找到,將其刪除,這裏的szUsername和szIRCUsername的名稱是相同,很不解
{
g_cMainCtrl . m_cMac . DelLogin ( sLine . Token (3, " " ), sLine . Token (3, " " ));
}
// If the bot itself is kicked, rejoin, and send "screw you %s!"
//如果bot自己被,踢出頻道,則重新登錄
if (! sLine . Token (3, " " ). Compare ( g_cMainCtrl . m_sUserName ))
{
CString sName ( sLine . Token (1, ":" ). Token (0, "!" ). CStr ());
m_bJoined = false ;
SendRawFormat ( "JOIN %s %s/r/n" , //發送加入頻道消息
g_cMainCtrl . m_cBot . si_mainchan . sValue . CStr (),
g_cMainCtrl . m_cBot . si_chanpass . sValue . CStr ());
SendRawFormat ( "PRIVMSG %s :screw you %s!/r/n" , g_cMainCtrl . m_cBot . si_mainchan . sValue . CStr (), sName . CStr ());
//發送私有消息“screw you”
}
}
// Someone changed his nickname
//處理標準消息,其他用戶修改暱稱的消息
else if (! sLine . Token (1, " " ). Compare ( "NICK" ))
{
// Check if hes logged in, if so, replace the username in CMac
CString sOldNick ( sLine . Token (1, ":" ). Token (0, "!" ). CStr ());
if (! strstr ( sLine . Str (), " :" ))
{
continue ;
}
CString sNewNick ( strstr ( sLine . Str (), " :" ));
if ( sOldNick . Compare ( "" ) && sNewNick . Compare ( "" ))
{
login * pLogin = g_cMainCtrl . m_cMac . FindLogin ( sOldNick );
if ( pLogin )
{
pLogin -> sIRCUsername . Assign ( sNewNick );
}
if (! sOldNick . Compare ( g_cMainCtrl . m_sUserName ))
{
g_cMainCtrl . m_sUserName . Assign ( sNewNick );
}
}
}
// Someone left the channel 處理其他人離開頻道的消息
else if (! sLine . Token (1, " " ). Compare ( "PART" ) || ! sLine . Token (1, " " ). Compare ( "QUIT" ))
{
// Check if hes logged in, if so, log him out
login * pLogin = g_cMainCtrl . m_cMac . FindLogin ( sLine . Token (1, ":" ). Token (0, "!" ));
if ( pLogin )
{
g_cMainCtrl . m_cMac . DelLogin ( sLine . Token (1, ":" ). Token (0, "!" ), sLine . Token (1, ":" ). Token (0, "!" ));
}
}
}
else
{ // We didn't receive a valid line, or the server closed the connection
Fail ();
continue ;
}
} //end_if_1
} //end while
return NULL ;
}