2 // This file is (C) 2004 Royce Mitchell III
3 // and released under the BSD & LGPL licenses
6 #pragma warning ( disable : 4786 )
12 #include "IRCClient.h"
17 #include "SplitJoin.h"
21 using std::stringstream
;
24 bool IRCClient::_debug
= true;
26 IRCClient::IRCClient()
27 : _timeout(10*60*1000), _inRun(false)
31 bool IRCClient::Connect ( const string
& server
, short port
)
35 Attach ( suTcpSocket() );
36 if ( !suConnect ( *this, server
.c_str(), port
) )
42 IRCClient::User ( const string
& user
, const string
& mode
,
43 const string
& network
, const string
& realname
)
46 buf
= "USER " + user
+ " \"" + mode
+ "\" \"" + network
+ "\" :" + realname
+ "\n";
51 IRCClient::Nick ( const string
& nick
)
54 return Send ( "NICK " + _nick
+ "\n" );
58 IRCClient::Mode ( const string
& mode
)
60 return Send ( "MODE " + _nick
+ " " + mode
+ "\n" );
64 IRCClient::Names ( const string
& channel
)
66 return Send ( "NAMES " + channel
+ "\n" );
70 IRCClient::Mode ( const string
& channel
, const string
& mode
, const string
& target
)
72 return Send ( "MODE " + channel
+ " " + mode
+ " " + target
+ "\n" );
76 IRCClient::Join ( const string
& channel
)
78 return Send ( "JOIN " + channel
+ "\n" );
82 IRCClient::PrivMsg ( const string
& to
, const string
& text
)
84 return Send ( "PRIVMSG " + to
+ " :" + text
+ "\n" );
88 IRCClient::Part ( const string
& channel
, const string
& text
)
90 return Send ( "PART " + channel
+ " :" + text
+ "\n" );
94 IRCClient::Quit ( const string
& text
)
96 return Send( "QUIT :" + text
+ "\n");
99 bool IRCClient::_Recv ( string
& buf
)
101 bool b
= (recvUntil ( buf
, '\n', _timeout
) > 0);
104 printf ( ">> %s", buf
.c_str() );
105 if ( buf
[buf
.length()-1] != '\n' )
111 bool IRCClient::Send ( const string
& buf
)
115 printf ( "<< %s", buf
.c_str() );
116 if ( buf
[buf
.length()-1] != '\n' )
119 return ( buf
.length() == (size_t)send ( *this, buf
.c_str(), buf
.length(), 0 ) );
122 bool IRCClient::OnPing( const string
& text
)
124 return Send( "PONG " + text
+ "\n" );
128 int THREADAPI
IRCClient::Callback ( IRCClient
* irc
)
130 return irc
->Run ( false );
133 int IRCClient::Run ( bool launch_thread
)
135 if ( (SOCKET
)*this == INVALID_SOCKET
)
137 if ( _inRun
) return 1;
140 ThreadPool::Instance().Launch ( (ThreadPoolFunc
*)IRCClient::Callback
, this );
144 if ( _debug
) printf ( "IRCClient::Run() - waiting for responses\n" );
148 if ( !strnicmp ( buf
.c_str(), "NOTICE ", 7 ) )
150 //printf ( "recv'd NOTICE msg...\n" );
154 else if ( !strnicmp ( buf
.c_str(), "PING ", 5 ) )
156 const char* p
= &buf
[5]; // point to first char after "PING "
157 while ( *p
== ':' ) // then read past the colons
159 const char* p2
= strpbrk ( p
, "\r\n" ); // find the end of line
160 string
text ( p
, p2
-p
); // and set the text
163 else if ( buf
[0] == ':' )
165 const char* p
= &buf
[1]; // skip first colon...
166 const char* p2
= strpbrk ( p
, " !" );
169 printf ( "!!!:OnRecv failure 0: ", buf
.c_str() );
172 string
src ( p
, p2
-p
);
175 printf ( "!!!:OnRecv failure 0.5: %s", buf
.c_str() );
181 p2
= strchr ( p
, ' ' );
184 printf ( "!!!:OnRecv failure 1: %s", buf
.c_str() );
187 //string srchost ( p, p2-p );
190 p2
= strchr ( p
, ' ' );
193 printf ( "!!!:OnRecv failure 2: %s", buf
.c_str() );
196 string
cmd ( p
, p2
-p
);
198 p2
= strpbrk ( p
, " :" );
201 printf ( "!!!:OnRecv failure 3: %s", buf
.c_str() );
204 string
tgt ( p
, p2
-p
);
206 p
+= strspn ( p
, " " );
210 p
+= strspn ( p
, " " );
214 p2
= strpbrk ( p
, "\r\n" );
217 printf ( "!!!:OnRecv failure 4: %s", buf
.c_str() );
220 string
text ( p
, p2
-p
);
222 if ( cmd
== "privmsg" )
226 printf ( "!!!:OnRecv failure 5 (PRIVMSG w/o target): %s", buf
.c_str() );
230 OnChannelMsg ( tgt
, src
, text
);
232 OnPrivMsg ( src
, text
);
234 else if ( cmd
== "mode" )
236 // two diff. kinds of mode notifications...
237 //printf ( "[MODE] src='%s' cmd='%s' tgt='%s' text='%s'", src.c_str(), cmd.c_str(), tgt.c_str(), text.c_str() );
240 // [MODE] src=Relic3_14 cmd=mode tgt=Relic3_14 text=+i
241 // channel mode change:
242 // [MODE] src=Royce3 cmd=mode tgt=#Royce3 text=+o Relic3_14
246 p2
= strchr ( p
, ' ' );
248 OnChannelMode ( tgt
, text
);
251 string
user ( p
, p2
-p
);
253 p
+= strspn ( p
, " " );
254 OnUserModeInChannel ( src
, tgt
, user
, p
);
258 OnMode ( tgt
, text
);
260 else if ( cmd
== "join" )
262 OnJoin ( src
, text
);
264 else if ( isdigit(cmd
[0]) )
266 int i
= atoi(cmd
.c_str());
269 case 1: // "Welcome!" - i.e. it's okay to issue commands now...
272 case 353: // user list for channel....
275 p2
= strpbrk ( p
, " :" );
277 string
channel ( p
, p2
-p
);
278 p
= strchr ( p2
, ':' );
281 vector
<string
> users
;
284 p2
= strchr ( p
, ' ' );
287 users
.push_back ( string ( p
, p2
-p
) );
289 p
+= strspn ( p
, " " );
291 OnChannelUsers ( channel
, users
);
294 case 366: // END of user list for channel
297 p2
= strpbrk ( p
, " :" );
299 string
channel ( p
, p2
-p
);
300 OnEndChannelUsers ( channel
);
304 if ( _debug
) printf ( "unknown command %i: %s", i
, buf
.c_str() );
310 if ( _debug
) printf ( "unrecognized ':' response: %s", buf
.c_str() );
315 if ( _debug
) printf ( "unrecognized irc msg: %s", buf
.c_str() );
319 if ( _debug
) printf ( "IRCClient::Run() - exiting\n" );