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::Action ( const string
& to
, const string
& text
)
90 return Send ( "PRIVMSG " + to
+ " :" + (char)1 + "ACTION " + text
+ (char)1 + '\n' );
94 IRCClient::Part ( const string
& channel
, const string
& text
)
96 return Send ( "PART " + channel
+ " :" + text
+ "\n" );
100 IRCClient::Quit ( const string
& text
)
102 return Send( "QUIT :" + text
+ "\n");
105 bool IRCClient::_Recv ( string
& buf
)
107 bool b
= (recvUntil ( buf
, '\n', _timeout
) > 0);
110 printf ( ">> %s", buf
.c_str() );
111 if ( buf
[buf
.length()-1] != '\n' )
117 bool IRCClient::Send ( const string
& buf
)
121 printf ( "<< %s", buf
.c_str() );
122 if ( buf
[buf
.length()-1] != '\n' )
125 return ( buf
.length() == (size_t)send ( *this, buf
.c_str(), buf
.length(), 0 ) );
128 bool IRCClient::OnPing( const string
& text
)
130 return Send( "PONG " + text
+ "\n" );
134 int THREADAPI
IRCClient::Callback ( IRCClient
* irc
)
136 return irc
->Run ( false );
139 int IRCClient::Run ( bool launch_thread
)
141 if ( (SOCKET
)*this == INVALID_SOCKET
)
143 if ( _inRun
) return 1;
146 ThreadPool::Instance().Launch ( (ThreadPoolFunc
*)IRCClient::Callback
, this );
150 if ( _debug
) printf ( "IRCClient::Run() - waiting for responses\n" );
154 if ( !strnicmp ( buf
.c_str(), "NOTICE ", 7 ) )
156 //printf ( "recv'd NOTICE msg...\n" );
160 else if ( !strnicmp ( buf
.c_str(), "PING ", 5 ) )
162 const char* p
= &buf
[5]; // point to first char after "PING "
163 while ( *p
== ':' ) // then read past the colons
165 const char* p2
= strpbrk ( p
, "\r\n" ); // find the end of line
166 string
text ( p
, p2
-p
); // and set the text
169 else if ( buf
[0] == ':' )
171 const char* p
= &buf
[1]; // skip first colon...
172 const char* p2
= strpbrk ( p
, " !" );
175 printf ( "!!!:OnRecv failure 0: ", buf
.c_str() );
178 string
src ( p
, p2
-p
);
181 printf ( "!!!:OnRecv failure 0.5: %s", buf
.c_str() );
187 p2
= strchr ( p
, ' ' );
190 printf ( "!!!:OnRecv failure 1: %s", buf
.c_str() );
193 //string srchost ( p, p2-p );
196 p2
= strchr ( p
, ' ' );
199 printf ( "!!!:OnRecv failure 2: %s", buf
.c_str() );
202 string
cmd ( p
, p2
-p
);
204 p2
= strpbrk ( p
, " :" );
207 printf ( "!!!:OnRecv failure 3: %s", buf
.c_str() );
210 string
tgt ( p
, p2
-p
);
212 p
+= strspn ( p
, " " );
216 p
+= strspn ( p
, " " );
220 p2
= strpbrk ( p
, "\r\n" );
223 printf ( "!!!:OnRecv failure 4: %s", buf
.c_str() );
226 string
text ( p
, p2
-p
);
228 if ( cmd
== "privmsg" )
232 printf ( "!!!:OnRecv failure 5 (PRIVMSG w/o target): %s", buf
.c_str() );
238 p2
= strchr ( p
, ' ' );
239 if ( !p2
) p2
= p
+ strlen(p
);
240 cmd
= string ( p
, p2
-p
);
243 p2
= strchr ( p
, 1 );
246 printf ( "!!!:OnRecv failure 6 (no terminating \x01 for initial \x01 found: %s", buf
.c_str() );
249 text
= string ( p
, p2
-p
);
250 if ( cmd
== "action" )
253 OnChannelAction ( tgt
, src
, text
);
255 OnPrivAction ( src
, text
);
259 printf ( "!!!:OnRecv failure 7 (unrecognized \x01 command '%s': %s", cmd
.c_str(), buf
.c_str() );
266 OnChannelMsg ( tgt
, src
, text
);
268 OnPrivMsg ( src
, text
);
271 else if ( cmd
== "mode" )
273 // two diff. kinds of mode notifications...
274 //printf ( "[MODE] src='%s' cmd='%s' tgt='%s' text='%s'", src.c_str(), cmd.c_str(), tgt.c_str(), text.c_str() );
277 // [MODE] src=Nick cmd=mode tgt=Nick text=+i
278 // channel mode change:
279 // [MODE] src=Nick cmd=mode tgt=#Channel text=+o Nick
283 p2
= strchr ( p
, ' ' );
286 string
mode ( p
, p2
-p
);
288 p
+= strspn ( p
, " " );
289 OnUserModeInChannel ( src
, tgt
, mode
, trim(p
) );
292 OnChannelMode ( tgt
, text
);
295 OnMode ( tgt
, text
);
297 else if ( cmd
== "join" )
299 OnJoin ( src
, text
);
301 else if ( cmd
== "part" )
303 OnPart ( src
, text
);
305 else if ( cmd
== "nick" )
307 OnNick ( src
, text
);
309 else if ( isdigit(cmd
[0]) )
311 int i
= atoi(cmd
.c_str());
314 case 1: // "Welcome!" - i.e. it's okay to issue commands now...
317 case 353: // user list for channel....
320 p2
= strpbrk ( p
, " :" );
322 string
channel ( p
, p2
-p
);
323 p
= strchr ( p2
, ':' );
326 vector
<string
> users
;
329 p2
= strchr ( p
, ' ' );
332 users
.push_back ( string ( p
, p2
-p
) );
334 p
+= strspn ( p
, " " );
336 OnChannelUsers ( channel
, users
);
339 case 366: // END of user list for channel
342 p2
= strpbrk ( p
, " :" );
344 string
channel ( p
, p2
-p
);
345 OnEndChannelUsers ( channel
);
349 if ( _debug
) printf ( "unknown command %i: %s", i
, buf
.c_str() );
355 if ( strstr ( buf
.c_str(), "ACTION" ) )
357 printf ( "ACTION: " );
358 for ( int i
= 0; i
< buf
.size(); i
++ )
359 printf ( "%c(%xh)", buf
[i
], (unsigned)(unsigned char)buf
[i
] );
361 else if ( _debug
) printf ( "unrecognized ':' response: %s", buf
.c_str() );
366 if ( _debug
) printf ( "unrecognized irc msg: %s", buf
.c_str() );
370 if ( _debug
) printf ( "IRCClient::Run() - exiting\n" );