Skip to content

Commit 90d6934

Browse files
committed
added quotes
IRC Client: - added nick member Bot module: - register nick with irc::client General: - minor tweaks ... Quotes Module: - added !quote = no argument: random quote or next result = text search in database = selection by id - added !addquote
1 parent c20c600 commit 90d6934

14 files changed

+306
-19
lines changed

CMakeLists.txt

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
cmake_minimum_required(VERSION 2.6)
2-
project(weberknecht)
32

3+
SET(BOOST_INCLUDE /usr/include/boost-1_38)
4+
5+
project(weberknecht)
6+
SET(CMAKE_CXX_FLAGS "-Wall -Werror -ansi -pedantic -isystem ${BOOST_INCLUDE}")
47
SET(CMAKE_BUILD_TYPE Debug)
58

9+
610
add_subdirectory(src)
711

812
include_directories(${WEBERKNECHT_SOURCE_DIR}/src/)

src/CMakeLists.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
add_subdirectory(irc)
22
add_subdirectory(sqlite)
33

4-
add_executable(weberknecht main.cpp weberknecht.cpp userdb.cpp)
5-
target_link_libraries(weberknecht boost_system boost_regex irc sqlite_wrapped)
4+
add_executable(weberknecht main.cpp weberknecht.cpp quotes.cpp)
5+
target_link_libraries(weberknecht boost_system boost_regex irc sqlite3 sqlite_wrapped)

src/irc/client.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <boost/bind.hpp>
55
#include <boost/algorithm/string.hpp>
6+
#include <boost/lexical_cast.hpp>
67

78
#include "message.h"
89
#include "client.h"
@@ -126,7 +127,7 @@ namespace weberknecht {
126127
if( !error )
127128
{
128129
boost::asio::async_read_until( socket_,
129-
buf_, boost::regex("\r\n$"),
130+
buf_, boost::regex( "\r\n$" ),
130131
boost::bind( &client::receive_handler,
131132
this,
132133
boost::asio::placeholders::error,
@@ -156,7 +157,7 @@ namespace weberknecht {
156157
while( std::getline( buf_stream, next ) )
157158
{
158159
message m;
159-
if( m.parseNew( next ) )
160+
if( m.parseNew( boost::lexical_cast<std::string>( next.c_str() ) ) )
160161
{
161162
handleMsg( "all", m );
162163
handleMsg( m.command(), m );

src/irc/client.h

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ namespace weberknecht {
4848

4949
void disconnect();
5050

51+
std::string nick;
52+
5153
private:
5254
void send( const std::string& msg );
5355
void close();
@@ -69,6 +71,7 @@ namespace weberknecht {
6971
std::deque<std::string> out_;
7072

7173
boost::asio::streambuf buf_;
74+
//boost::asio::streambuf buf_;
7275

7376
class msgHandler {
7477
public:

src/irc/message.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11

2+
#include <iostream>
3+
4+
#include <boost/lexical_cast.hpp>
25
#include <boost/bind.hpp>
36
#include <boost/algorithm/string.hpp>
47
#include <boost/spirit/include/classic_core.hpp>
5-
#include <boost/spirit/actor/increment_actor.hpp>
8+
#include <boost/spirit/include/classic_increment_actor.hpp>
69

710
#include "message.h"
811

@@ -84,9 +87,10 @@ namespace weberknecht {
8487
rule<> start, prefix, command, params, trailing, middle, space, nospcrlfcl;
8588

8689
space = +ch_p( ' ' );
87-
nospcrlfcl = range_p( 0x01, 0x09 ) | range_p( 0x0B, 0x0C ) | range_p( 0x0E, 0x1F ) | range_p( 0x21, 0x39 ) | range_p( 0x3B, 0xFF );
90+
//nospcrlfcl = range_p( 0x01, 0x09 ) | range_p( 0x0B, 0x0C ) | range_p( 0x0E, 0x1F ) | range_p( 0x21, 0x39 ) | range_p( 0x3B, 0xFF );
91+
nospcrlfcl = ~ch_p( 0x0A ) & ~ch_p( 0x0D ) & ~ch_p( 0x20 ) & ~ch_p( 0x3A );
8892

89-
start = !( ch_p(':') >> prefix >> space ) >> command >> params >> ch_p('\r');
93+
start = !( ch_p( ':' ) >> prefix >> space ) >> command >> params >> ch_p( '\r' );
9094

9195
prefix = (+nospcrlfcl)[assign_a( prefix_ )];
9296

src/main.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,17 @@ using namespace weberknecht;
1212
int main( int argc, char** argv )
1313
{
1414
boost::asio::io_service io;
15-
bot knecht( argv[1], "6667", io );
15+
bot knecht( argv[1], "6667", "../data/weberknecht.db", io );
1616

1717
knecht.addNick( "weberknecht" );
1818
knecht.addNick( "testknecht" );
1919

2020
knecht.addChannel( "#weberknecht" );
2121

22-
knecht.connect();
23-
24-
io.run();
22+
if( knecht.connect() )
23+
{
24+
io.run();
25+
}
2526

2627
return 0;
2728
}

src/quotes.cpp

+182
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
2+
#include <iostream>
3+
#include <ctime>
4+
5+
#include <boost/bind.hpp>
6+
#include <boost/spirit/include/classic_core.hpp>
7+
#include <boost/lexical_cast.hpp>
8+
#include <boost/algorithm/string/replace.hpp>
9+
#include <boost/random.hpp>
10+
11+
#include "quotes.h"
12+
#include "spirit.h"
13+
14+
using namespace std;
15+
using namespace BOOST_SPIRIT_CLASSIC_NS;
16+
17+
namespace weberknecht {
18+
quotes::quotes( irc::client& c, Database& db )
19+
: c_( c ),
20+
quote_( db ),
21+
numResults_( -1 ),
22+
currResult_( -1 )
23+
{
24+
ADD_MSG_HANDLER( "PRIVMSG", quotes, quotes_handler, 0 )
25+
}
26+
27+
quotes::~quotes()
28+
{
29+
quote_.free_result();
30+
}
31+
32+
bool quotes::quotes_handler( const irc::message& m )
33+
{
34+
std::string action;
35+
std::string selector;
36+
rule< > quote_parser, char_p;
37+
38+
quote_parser = ( str_p( "!quote" ) | str_p( "!addquote" ) )[assign_a(action)]
39+
>> !(+ch_p( ' ' ) >> !( (+(char_p) )[assign_a(selector)] ) ) >> *ch_p( ' ' );
40+
char_p = ~ch_p( 0x0A ) & ~ch_p( 0x0D ) & ~ch_p( 0x3A );
41+
42+
if( !quote_.Connected() )
43+
{
44+
cerr << "No database connection!" << endl;
45+
}
46+
47+
if( m.param( 0 ) == c_.nick ) return false;
48+
49+
if( parse( m.param( 1 ).c_str(), quote_parser ).full )
50+
{
51+
if( action == "!quote" )
52+
{
53+
std::string sql_select_count = "SELECT COUNT(text) FROM quotes WHERE channel='" + m.param( 0 ) + "'";
54+
std::string sql_select = "SELECT text FROM quotes WHERE channel='" + m.param( 0 ) + "' AND ";
55+
56+
if( selector.length() != 0 )
57+
{
58+
std::list<std::string> select_list;
59+
std::string tmp;
60+
std::string quoteID = "0";
61+
rule<> selector_rule, quoted, word;
62+
selector_rule = (+digit_p)[assign_a( quoteID )] |
63+
(*( *ch_p( ' ' ) >> ( quoted[push_back_a( select_list, tmp )] | word[push_back_a( select_list )] ) >> *ch_p( ' ' ) ) );
64+
quoted = ( ch_p( '"' ) >> *( ( *ch_p(' ') >> word >> *ch_p( ' ' ) )[append_a( tmp )] ) >> ch_p( '"' ) ) |
65+
( ch_p( '\'' ) >> *( ( *ch_p(' ') >> word >> *ch_p( ' ' ) )[append_a( tmp )] ) >> ch_p( '\'' ) );
66+
67+
word = +( char_p & ~ch_p( '"' ) & ~ch_p( '\'' ) );
68+
69+
sql_select_count += " AND ";
70+
71+
if( parse( selector.c_str(), selector_rule ).full )
72+
{
73+
if( quoteID == "0" )
74+
{
75+
std::list<std::string>::iterator it;
76+
for( it = select_list.begin(); it != --select_list.end(); ++it )
77+
{
78+
sql_select += "text LIKE '%" + *it + "%' OR ";
79+
sql_select_count += "text LIKE '%" + *it + "%' OR ";
80+
}
81+
82+
sql_select += "text LIKE '%" + *it + "%';";
83+
sql_select_count += "text LIKE '%" + *it + "%';";
84+
}
85+
else
86+
sql_select += "id=" + quoteID + ";";
87+
88+
cout << sql_select << endl;
89+
if( numResults_ != -1 )
90+
quote_.free_result();
91+
92+
numResults_ = quote_.get_count( sql_select_count );
93+
quote_.free_result();
94+
95+
cout << "Number of results: " << numResults_ << endl;
96+
currResult_ = -1;
97+
98+
quote_.get_result( sql_select );
99+
if( numResults_ || quoteID != "0" )
100+
{
101+
quote_.fetch_row();
102+
currResult_ = 1;
103+
std::string text = quote_.getstr();
104+
if( numResults_ < 2 )
105+
{
106+
quote_.free_result();
107+
numResults_ = -1;
108+
}
109+
else
110+
text += " ( " + boost::lexical_cast<std::string>(numResults_ - currResult_++) + " left )";
111+
112+
c_ << irc::PRIVMSG( m.param( 0 ), text );
113+
}
114+
return true;
115+
}
116+
}
117+
if( numResults_ == -1 )
118+
{
119+
if( numResults_ != -1 )
120+
quote_.free_result();
121+
122+
int max = quote_.get_count( sql_select_count );
123+
boost::mt19937 rng( time( NULL ) ) ;
124+
boost::uniform_int<> uni(1, max);
125+
boost::variate_generator<boost::mt19937&, boost::uniform_int<> >
126+
die(rng, uni);
127+
128+
sql_select += " id=" + boost::lexical_cast<std::string>( die() ) + ";";
129+
130+
cout << sql_select << endl;
131+
quote_.free_result();
132+
133+
c_ << irc::PRIVMSG( m.param( 0 ), quote_.get_string( sql_select ) );
134+
quote_.free_result();
135+
136+
return true;
137+
}
138+
if( (currResult_ <= numResults_) && (numResults_ > 0 ) )
139+
{
140+
quote_.fetch_row();
141+
142+
std::string text = quote_.getstr();
143+
text += " ( " + boost::lexical_cast<std::string>(numResults_ - currResult_++) + " left )";
144+
145+
if( numResults_ < currResult_ )
146+
{
147+
quote_.free_result();
148+
numResults_ = -1;
149+
}
150+
151+
c_ << irc::PRIVMSG( m.param( 0 ), text );
152+
153+
return true;
154+
}
155+
}
156+
else
157+
{
158+
if( selector.length() != 0 )
159+
{
160+
if( numResults_ != -1 )
161+
quote_.free_result();
162+
163+
std::string text = m.param( 1 ).substr( 10, m.param( 1 ).length() );
164+
boost::replace_all( text, "'", "\"" );
165+
cout << text << endl;
166+
167+
if( quote_.execute( "INSERT INTO quotes (text, channel) VALUES ('" +text+ "', '" +m.param(0)+ "' );" ) )
168+
{
169+
quote_.free_result();
170+
long id = quote_.get_count( "SELECT MAX(id) FROM quotes WHERE channel='" + m.param(0) + "';");
171+
c_ << irc::PRIVMSG( m.param(0),
172+
"Added Quote with id: " + boost::lexical_cast<std::string>( id) + "." );
173+
quote_.free_result();
174+
}
175+
}
176+
return true;
177+
}
178+
}
179+
180+
return false;
181+
}
182+
} // end weberknecht

src/quotes.h

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
#ifndef QUOTES_H
3+
#define QUOTES_H
4+
5+
#include "irc/client.h"
6+
#include "sqlite/Query.h"
7+
8+
namespace weberknecht {
9+
10+
class quotes {
11+
public:
12+
quotes( irc::client& c, Database& db );
13+
~quotes();
14+
15+
private:
16+
irc::client& c_;
17+
Query quote_;
18+
19+
long numResults_;
20+
long currResult_;
21+
22+
bool quotes_handler( const irc::message& m );
23+
};
24+
25+
} // end namespace
26+
27+
#endif

src/spirit.h

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
#ifndef SPIRIT_H
3+
#define SPIRIT_H
4+
5+
#include <boost/spirit/include/classic_core.hpp>
6+
7+
8+
9+
namespace weberknecht {
10+
using namespace BOOST_SPIRIT_CLASSIC_NS;
11+
12+
template< typename T >
13+
class append_action
14+
{
15+
public:
16+
17+
explicit append_action(T& ref_)
18+
: ref(ref_){}
19+
20+
template<typename T2>
21+
void operator()(T2 const& val) const
22+
{
23+
ref.append( val);
24+
}
25+
26+
template<typename IteratorT>
27+
void operator()(
28+
IteratorT const& first,
29+
IteratorT const& last) const
30+
{
31+
ref.append(first,last);
32+
}
33+
34+
private:
35+
T& ref;
36+
};
37+
38+
template< typename T > append_action<T> append_a( T& ref)
39+
{
40+
return append_action<T>( ref );
41+
}
42+
43+
} // end weberknecht
44+
45+
#endif

src/sqlite/Database.h

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ typedef __int64 int64_t;
4747
#include <stdint.h>
4848
#endif
4949

50+
#include <sqlite3.h>
51+
5052
#ifdef SQLITEW_NAMESPACE
5153
namespace SQLITEW_NAMESPACE {
5254
#endif

src/sqlite/Query.h

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ typedef __int64 int64_t;
4545
#include <stdint.h>
4646
#endif
4747

48+
#include "Database.h"
49+
4850

4951
#ifdef SQLITEW_NAMESPACE
5052
namespace SQLITEW_NAMESPACE {

src/userdb.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

2-
#ifndef USER_H
3-
#define USER_H
2+
#ifndef USERDB_H
3+
#define USERDB_H
44

55
#include <boost/unordered_map.hpp>
66

0 commit comments

Comments
 (0)