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"
22 using std::stringstream
;
25 bool IRCClient::_debug
= true;
27 // see rfc1459 for IRC-Protocoll Reference
29 IRCClient::IRCClient()
30 : _timeout(10*60*1000), _inRun(false)
34 bool IRCClient::Connect ( const string
& server
, short port
)
38 Attach ( suTcpSocket() );
39 if ( !suConnect ( *this, server
.c_str(), port
) )
45 IRCClient::User ( const string
& user
, const string
& mode
,
46 const string
& network
, const string
& realname
)
49 buf
= "USER " + user
+ " \"" + mode
+ "\" \"" + network
+ "\" :" + realname
+ "\n";
54 IRCClient::Nick ( const string
& nick
)
57 Send ( "NICK " + _nick
+ "\n" );
58 PrivMsg ("NickServ", "IDENTIFY " + (string
)PASS
);
63 IRCClient::Mode ( const string
& mode
)
65 return Send ( "MODE " + _nick
+ " " + mode
+ "\n" );
69 IRCClient::Names ( const string
& channel
)
71 return Send ( "NAMES " + channel
+ "\n" );
75 IRCClient::Mode ( const string
& channel
, const string
& mode
, const string
& target
)
77 return Send ( "MODE " + channel
+ " " + mode
+ " " + target
+ "\n" );
81 IRCClient::Join ( const string
& channel
)
83 return Send("JOIN " + channel
+ "\n");
87 IRCClient::PrivMsg ( const string
& to
, const string
& text
)
89 return Send ( "PRIVMSG " + to
+ " :" + text
+ '\n' );
93 IRCClient::Action ( const string
& to
, const string
& text
)
95 return Send ( "PRIVMSG " + to
+ " :" + (char)1 + "ACTION " + text
+ (char)1 + '\n' );
99 IRCClient::Part ( const string
& channel
, const string
& text
)
101 return Send ( "PART " + channel
+ " :" + text
+ "\n" );
105 IRCClient::Quit ( const string
& text
)
107 return Send( "QUIT :" + text
+ "\n");
110 bool IRCClient::_Recv ( string
& buf
)
112 bool b
= (recvUntil ( buf
, '\n', _timeout
) > 0);
115 printf ( ">> %s", buf
.c_str() );
116 if ( buf
[buf
.length()-1] != '\n' )
122 bool IRCClient::Send ( const string
& buf
)
126 printf ( "<< %s", buf
.c_str() );
127 if ( buf
[buf
.length()-1] != '\n' )
130 return ( buf
.length() == (size_t)send ( *this, buf
.c_str(), buf
.length(), 0 ) );
133 bool IRCClient::OnPing( const string
& text
)
135 return Send( "PONG " + text
+ "\n" );
139 int THREADAPI
IRCClient::Callback ( IRCClient
* irc
)
141 return irc
->Run ( false );
144 int IRCClient::Run ( bool launch_thread
)
146 if ( (SOCKET
)*this == INVALID_SOCKET
)
148 if ( _inRun
) return 1;
151 ThreadPool::Instance().Launch ( (ThreadPoolFunc
*)IRCClient::Callback
, this );
155 if ( _debug
) printf ( "IRCClient::Run() - waiting for responses\n" );
159 if ( !strnicmp ( buf
.c_str(), "NOTICE ", 7 ) )
161 //printf ( "recv'd NOTICE msg...\n" );
165 else if ( !strnicmp ( buf
.c_str(), "PING ", 5 ) )
167 const char* p
= &buf
[5]; // point to first char after "PING "
168 while ( *p
== ':' ) // then read past the colons
170 const char* p2
= strpbrk ( p
, "\r\n" ); // find the end of line
171 string
text ( p
, p2
-p
); // and set the text
174 else if ( buf
[0] == ':' )
176 const char* p
= &buf
[1]; // skip first colon...
177 const char* p2
= strpbrk ( p
, " !" );
180 printf ( "!!!:OnRecv failure 0: ", buf
.c_str() );
183 string
src ( p
, p2
-p
);
186 printf ( "!!!:OnRecv failure 0.5: %s", buf
.c_str() );
192 p2
= strchr ( p
, ' ' );
195 printf ( "!!!:OnRecv failure 1: %s", buf
.c_str() );
198 //string srchost ( p, p2-p );
201 p2
= strchr ( p
, ' ' );
204 printf ( "!!!:OnRecv failure 2: %s", buf
.c_str() );
207 string
cmd ( p
, p2
-p
);
209 p2
= strpbrk ( p
, " :" );
212 printf ( "!!!:OnRecv failure 3: %s", buf
.c_str() );
215 string
tgt ( p
, p2
-p
);
217 p
+= strspn ( p
, " " );
221 p
+= strspn ( p
, " " );
225 p2
= strpbrk ( p
, "\r\n" );
228 printf ( "!!!:OnRecv failure 4: %s", buf
.c_str() );
231 string
text ( p
, p2
-p
);
233 if ( cmd
== "privmsg" )
237 printf ( "!!!:OnRecv failure 5 (PRIVMSG w/o target): %s", buf
.c_str() );
243 p2
= strchr ( p
, ' ' );
244 if ( !p2
) p2
= p
+ strlen(p
);
245 cmd
= string ( p
, p2
-p
);
248 p2
= strchr ( p
, 1 );
251 printf ( "!!!:OnRecv failure 6 (no terminating \x01 for initial \x01 found: %s", buf
.c_str() );
254 text
= string ( p
, p2
-p
);
255 if ( cmd
== "action" )
258 OnChannelAction ( tgt
, src
, text
);
260 OnPrivAction ( src
, text
);
264 printf ( "!!!:OnRecv failure 7 (unrecognized \x01 command '%s': %s", cmd
.c_str(), buf
.c_str() );
271 OnChannelMsg ( tgt
, src
, text
);
273 OnPrivMsg ( src
, text
);
276 else if ( cmd
== "mode" )
278 // two diff. kinds of mode notifications...
279 //printf ( "[MODE] src='%s' cmd='%s' tgt='%s' text='%s'", src.c_str(), cmd.c_str(), tgt.c_str(), text.c_str() );
282 // [MODE] src=Nick cmd=mode tgt=Nick text=+i
283 // channel mode change:
284 // [MODE] src=Nick cmd=mode tgt=#Channel text=+o Nick
288 p2
= strchr ( p
, ' ' );
291 string
mode ( p
, p2
-p
);
293 p
+= strspn ( p
, " " );
294 OnUserModeInChannel ( src
, tgt
, mode
, trim(p
) );
297 OnChannelMode ( tgt
, text
);
300 OnMode ( tgt
, text
);
302 else if ( cmd
== "join" )
305 OnJoin ( src
, text
);
307 else if ( cmd
== "part" )
309 OnPart ( src
, text
);
311 else if ( cmd
== "nick" )
313 OnNick ( src
, text
);
315 else if ( cmd
== "kick" )
319 else if ( isdigit(cmd
[0]) )
321 int i
= atoi(cmd
.c_str());
325 case 1: // "Welcome!" - i.e. it's okay to issue commands now...
329 case 353: // user list for channel....
332 p2
= strpbrk ( p
, " :" );
334 string
channel ( p
, p2
-p
);
335 p
= strchr ( p2
, ':' );
338 vector
<string
> users
;
341 p2
= strchr ( p
, ' ' );
344 users
.push_back ( string ( p
, p2
-p
) );
346 p
+= strspn ( p
, " " );
348 OnChannelUsers ( channel
, users
);
352 case 366: // END of user list for channel
355 p2
= strpbrk ( p
, " :" );
357 string
channel ( p
, p2
-p
);
358 OnEndChannelUsers ( channel
);
362 case 474: // You are banned
365 p2
= strpbrk ( p
, " :" );
367 string
channel ( p
, p2
-p
);
368 OnBanned ( channel
);
372 case 433: // Nick in Use
377 PrivMsg ("NickServ", "GHOST " + nick
+ " " + PASS
);
381 Join ( CHANNEL
); // this is because IRC client does not review if his commands were sucessfull
394 if ( _debug
) printf ( "unknown command %i: %s", i
, buf
.c_str() );
400 if ( strstr ( buf
.c_str(), "ACTION" ) )
402 printf ( "ACTION: " );
403 for ( int i
= 0; i
< buf
.size(); i
++ )
404 printf ( "%c(%xh)", buf
[i
], (unsigned)(unsigned char)buf
[i
] );
406 else if ( _debug
) printf ( "unrecognized ':' response: %s", buf
.c_str() );
411 if ( _debug
) printf ( "unrecognized irc msg: %s", buf
.c_str() );
415 if ( _debug
) printf ( "IRCClient::Run() - exiting\n" );