00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #ifndef USE_PCH
00017 #include "sys.h"
00018 #include <sstream>
00019 #include "debug.h"
00020 #endif
00021
00022 #include "MessageIn.h"
00023 #include "Authentication.h"
00024 #include "NoticeTarget.h"
00025 #include "keys.h"
00026 #include "Identity.inl"
00027 #include "Channel.h"
00028 #include "Nick.h"
00029 #include "PersistXML.h"
00030 #include "is_channel.h"
00031 #include "ClientSession.h"
00032 #include "Matcher.h"
00033 #include "Application.h"
00034 #include "WhoRequest.h"
00035
00036
00037
00038
00039
00040 void Identity::pass_as_is_to(MessageIn const& msg, std::ostream& os)
00041 {
00042 if (msg.has_prefix())
00043 os << ':' << msg.prefix_str() << ' ';
00044 if (msg.is_numeric())
00045 os << msg.numeric();
00046 else
00047 os << msg.uppercase_command();
00048 int number_of_parameters = msg.params_size();
00049 for (int param = 0; param < number_of_parameters; ++param)
00050 {
00051 os << ' ';
00052 if (param == number_of_parameters - 1)
00053 os << ':';
00054 os << msg.param(param);
00055 }
00056 os << "\r\n";
00057 }
00058
00059
00060
00061
00062
00063 void Identity::pass_as_is_to_server(ClientMessageIn const& msg)
00064 {
00065 bool blocked = true;
00066 switch (msg.key())
00067 {
00068 using namespace keys;
00069 case WHO:
00070 case WHOIS:
00071 case WHOWAS:
00072 blocked = false;
00073 break;
00074 default:
00075 break;
00076 }
00077 if (blocked && server_connection().state() < real_nick_sent)
00078 THROW_EXCEPTION(FatalError("Message to be passed as-is is blocked!"),
00079 "Identity::pass_as_is_to_server(" << msg << ") called while server connection in state " << server_connection().state() << '!');
00080 pass_as_is_to(msg, server_session());
00081 }
00082
00083
00084
00085
00086
00087 void Identity::pass_as_is_to_client(ServerMessageIn const& msg)
00088 {
00089 pass_as_is_to(msg, client_session());
00090 }
00091
00092 void Identity::new_client_message_received(ClientMessageIn const& msg)
00093 {
00094 DoutEntering(dc::debug, "Identity::new_client_message_received(" << msg << ")");
00095
00096 switch (msg.key())
00097 {
00098 using namespace keys;
00099 case PASS:
00100 Authentication::get(this, M_authentication);
00101 M_authentication->decode_pass(msg);
00102 break;
00103 case USER:
00104 if (M_ident == unknown_ident)
00105 M_ident = msg.param(0);
00106 M_real_name = msg.param(3);
00107 Authentication::get(this, M_authentication);
00108 M_authentication->decode_user(msg);
00109 break;
00110 case PING:
00111 {
00112 std::string server_name(server_connection().has_server() ? server_connection().server()->get_irc_name() : "noserver.pong.org");
00113 Prefix prefix(server_name);
00114 MessageOut msgout(default_priority(keys::PONG));
00115 client_session().queue_msg(msgout << prefix << keys::PONG << server_name << msg.params(0));
00116 break;
00117 }
00118 case SILENCE:
00119 {
00120
00121
00122 server_session().queue_msg_as_is(msg);
00123 break;
00124 }
00125 case OPER:
00126 case MAP:
00127 case WALLOPS:
00128 case WALLUSERS:
00129 {
00130
00131
00132 server_session().queue_msg_as_is(msg);
00133 break;
00134 }
00135 case STATS:
00136 case VERSION:
00137 {
00138
00139
00140 server_session().queue_msg_as_is(msg);
00141 break;
00142 }
00143 case WHO:
00144 {
00145 WhoRequest who_request(msg.client_session(), (msg.params_size() >= 3) ? msg.param(2) : msg.param(0), msg.param(1));
00146 if (msg.params().size() >= 1 && who_request.options().matches_against_channel() && is_channel(who_request.mask()))
00147 {
00148
00149 ClientSession::private_targets_type::iterator priv_iter = client_session().private_targets().find(who_request.mask());
00150 if (priv_iter != client_session().private_targets().end())
00151 {
00152 boost::static_pointer_cast<PrivateTarget>(priv_iter->second)->handle_who(who_request);
00153 break;
00154 }
00155 }
00156
00157 PseudoMessageOut pseudo_msg(default_priority(keys::WHO), safe_query);
00158 pseudo_msg.writeEventRequest(server_session(), &ServerSession::send_who_write_event, who_request);
00159 server_session().queue_msg(pseudo_msg);
00160 break;
00161 }
00162 case WHOIS:
00163 case WHOWAS:
00164 case LIST:
00165 {
00166
00167 Prefix prefix(msg);
00168
00169 MessageOut msgout(default_priority(msg.key()));
00170 server_session().queue_msg(msgout << prefix << msg.key() << msg.params(0));
00171 break;
00172 }
00173 case LINKS:
00174 break;
00175 case NICK:
00176
00177 msg.client_session().new_client_nick_received(msg.param(0));
00178 break;
00179 case QUIT:
00180 break;
00181 case KILL:
00182 {
00183 Prefix prefix(msg);
00184 MessageOut msgout(default_priority(msg.key()));
00185 try
00186 {
00187
00188 boost::shared_ptr<Target> nick = msg.client_session().get_nick(msg.param(0));
00189 server_session().queue_msg(msgout << prefix << msg.key() << nick << msg.params(1));
00190 }
00191 catch(unknown_target& error)
00192 {
00193 Debug(edragon::caught(error));
00194 server_session().queue_msg(msgout << prefix << msg.key() << msg.params(0));
00195 }
00196 break;
00197 }
00198 case MODE:
00199 case PRIVMSG:
00200 case NOTICE:
00201 {
00202 if (!msg.params().empty())
00203 {
00204 char c = *msg.params().front().start();
00205 if (c != '#' && c != '&')
00206 {
00207 if (msg.key() == MODE)
00208 {
00209
00210
00211 ASSERT(msg.param(0) == mynick()->in_name(client_session()));
00212 Prefix prefix(msg);
00213 MessageOut msgout(default_priority(msg.key()));
00214 server_session().queue_msg(msgout << prefix << msg.key() << mynick() << msg.params(1));
00215 break;
00216 }
00217 else
00218 {
00219 try
00220 {
00221
00222 msg.client_session().get_nick(msg.param(0))->new_client_message_received(msg);
00223 }
00224 catch(unknown_target& error)
00225 {
00226 Debug(edragon::caught(error));
00227
00228
00229
00230 server_session().queue_msg_as_is(msg);
00231 }
00232 }
00233 break;
00234 }
00235 }
00236
00237 }
00238 case INVITE:
00239 case CPRIVMSG:
00240 case CNOTICE:
00241 case JOIN:
00242 case PART:
00243 case KICK:
00244 case NAMES:
00245 case TOPIC:
00246 try
00247 {
00248
00249 Target::clientside_get_channel(*this, msg.param(0))->new_client_message_received(msg);
00250 }
00251 catch(unknown_target& error)
00252 {
00253 Debug(edragon::caught(error));
00254
00255
00256 server_session().queue_msg_as_is(msg);
00257 }
00258 break;
00259 }
00260 }
00261
00262 void Identity::do_quit(boost::shared_ptr<Nick> nick, std::string const& quit_message)
00263 {
00264 ASSERT(!nick->is_me());
00265 Prefix prefix(nick);
00266 MessageOut msgout(default_priority(keys::QUIT));
00267 client_session().queue_msg(msgout << prefix << keys::QUIT << JustInTimeLast(quit_message));
00268 NickData::common_channels_type& common_channels(nick->data().common_channels());
00269 Dout(dc::maps, "QUIT by " << nick << " who is on " << common_channels.size() << " common channels.");
00270 NickData::common_channels_type::iterator iter = common_channels.begin();
00271 while (iter != common_channels.end())
00272 {
00273
00274 (iter++)->second.lock()->sub_joined_nick(nick);
00275 }
00276 }
00277
00278 void Identity::new_server_message_received(ServerMessageIn const& msg)
00279 {
00280 ASSERT(!debug::secondary_connection);
00281 DoutEntering(dc::debug, "Identity::new_server_message_received(" << msg << ")");
00282
00283 switch (msg.key())
00284 {
00285 using namespace keys;
00286 case 315:
00287 {
00288 Prefix prefix(msg);
00289 MessageOut msgout(default_priority(msg.key()));
00290 client_session().queue_msg(msgout << prefix << msg.key() << mynick() << msg.params(1));
00291 #ifdef CWDEBUG
00292 WhoRequest who_request(server_session().current_who_request());
00293 ASSERT(who_request.mask() == msg.param(1));
00294 #endif
00295 server_session().pop_who_request();
00296 break;
00297 }
00298 case 324:
00299 {
00300 Prefix prefix(msg);
00301 MessageOut msgout(default_priority(msg.key()));
00302
00303 std::string my_nick_name(msg.param(0));
00304 ASSERT(my_nick_name == mynick()->in_name(msg.server_session()));
00305
00306 msgout << prefix << msg.key() << mynick();
00307
00308 try
00309 {
00310 boost::shared_ptr<Channel> channel(Target::serverside_get_channel(*this, msg.param(1)));
00311 msgout << channel;
00312 }
00313 catch (unknown_target& error)
00314 {
00315 Debug(edragon::caught(error));
00316 msgout << msg.param(1);
00317 }
00318 msgout << msg.params(2);
00319
00320 client_session().queue_msg(msgout);
00321 break;
00322 }
00323 case 329:
00324 {
00325 Prefix prefix(msg);
00326 MessageOut msgout(default_priority(msg.key()));
00327
00328 std::string my_nick_name(msg.param(0));
00329 ASSERT(my_nick_name == mynick()->in_name(msg.server_session()));
00330
00331 msgout << prefix << msg.key() << mynick();
00332 time_t creation_time = atol(msg.param(2).c_str());
00333 try
00334 {
00335 boost::shared_ptr<Channel> channel(Target::serverside_get_channel(*this, msg.param(1)));
00336 channel->set_creation_time(creation_time);
00337 msgout << channel;
00338 }
00339 catch (unknown_target& error)
00340 {
00341 Debug(edragon::caught(error));
00342 msgout << msg.param(1);
00343 }
00344 msgout << creation_time;
00345
00346 client_session().queue_msg(msgout);
00347 break;
00348 }
00349 case 352:
00350 {
00351
00352 WhoRequest who_request(server_session().current_who_request());
00353 Dout(dc::notice, "Decoding numeric 352 for WHO request " << who_request);
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 Prefix prefix(msg);
00364 MessageOut msgout(default_priority(msg.key()));
00365
00366 std::string my_nick_name(msg.param(0));
00367 ASSERT(my_nick_name == mynick()->in_name(msg.server_session()));
00368
00369 msgout << prefix << msg.key() << mynick();
00370 try
00371 {
00372 boost::shared_ptr<Channel> channel(Target::serverside_get_channel(*this, msg.param(1)));
00373 msgout << channel;
00374 }
00375 catch (unknown_target& error)
00376 {
00377 Debug(edragon::caught(error));
00378 msgout << msg.param(1);
00379 }
00380 std::string username(msg.param(2));
00381 std::string hostname(msg.param(3));
00382 std::string servername(msg.param(4));
00383 std::string flags(msg.param(6));
00384 std::string realname(msg.param(7));
00385 int hopcount = atoi(realname.c_str());
00386 realname = realname.substr(realname.find(' ') + 1);
00387 msgout << username << hostname << servername;
00388 try
00389 {
00390 boost::shared_ptr<Nick> nick(msg.server_session().get_nick(msg.param(5)));
00391 msgout << nick;
00392 nick->data().set_username(username);
00393 nick->data().set_hostname(hostname);
00394 nick->data().set_realname(realname);
00395 nick->data().set_hopcount(hopcount);
00396 nick->data().set_flags(Flags(network(), flags));
00397 }
00398 catch(unknown_target& error)
00399 {
00400 Debug(edragon::caught(error));
00401 msgout << msg.param(5);
00402 }
00403 msgout << flags << msg.params(7);
00404
00405 client_session().queue_msg(msgout);
00406 break;
00407 }
00408 case 354:
00409 {
00410
00411 WhoRequest who_request(server_session().current_who_request());
00412 Dout(dc::notice, "Decoding numeric 354 for WHO request " << who_request);
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 Prefix prefix(msg);
00428 MessageOut msgout(default_priority(msg.key()));
00429
00430 std::string my_nick_name(msg.param(0));
00431 ASSERT(my_nick_name == mynick()->in_name(msg.server_session()));
00432
00433 msgout << prefix << msg.key() << mynick();
00434
00435 int n = 0;
00436
00437 for (unsigned int field = 1; field < field_percentage; field <<= 1)
00438 {
00439 if ((who_request.options().fields() & field))
00440 {
00441
00442 ++n;
00443
00444 if (field == field_c)
00445 {
00446 try
00447 {
00448 boost::shared_ptr<Channel> channel(Target::serverside_get_channel(*this, msg.param(n)));
00449 msgout << channel;
00450 }
00451 catch (unknown_target& error)
00452 {
00453 Debug(edragon::caught(error));
00454 msgout << msg.param(n);
00455 }
00456 }
00457 else if (field == field_n)
00458 {
00459 try
00460 {
00461 boost::shared_ptr<Nick> nick(msg.server_session().get_nick(msg.param(n)));
00462 msgout << nick;
00463 int n2 = 0;
00464 for (unsigned int field2 = 1; field2 < field_percentage; field2 <<= 1)
00465 if ((who_request.options().fields() & field2))
00466 {
00467 ++n2;
00468 switch(field2)
00469 {
00470 case field_u:
00471 nick->data().set_username(msg.param(n2));
00472 break;
00473 case field_h:
00474 nick->data().set_hostname(msg.param(n2));
00475 break;
00476 case field_i:
00477 nick->data().set_ip(IPNumber(msg.param(n2)));
00478 break;
00479 case field_r:
00480 nick->data().set_realname(msg.param(n2));
00481 break;
00482 case field_d:
00483 nick->data().set_hopcount(atoi(msg.param(n2).c_str()));
00484 break;
00485 case field_f:
00486 nick->data().set_flags(Flags(network(), msg.param(n2)));
00487 break;
00488 case field_s:
00489 nick->data().set_servername(msg.param(n2));
00490 break;
00491 case field_l:
00492 nick->data().set_idletime(atoi(msg.param(n2).c_str()));
00493 break;
00494 case field_a:
00495 nick->data().set_accountname(msg.param(n2));
00496 break;
00497 }
00498 }
00499 }
00500 catch(unknown_target& error)
00501 {
00502 Debug(edragon::caught(error));
00503 msgout << msg.param(n);
00504 }
00505 }
00506 else
00507 msgout << msg.param(n);
00508 }
00509 }
00510
00511 client_session().queue_msg(msgout);
00512 break;
00513 }
00514 case 353:
00515 {
00516
00517 Prefix prefix(msg);
00518
00519 MessageOut msgout(default_priority(msg.key()));
00520
00521 boost::shared_ptr<Channel> channel(Target::serverside_get_channel(*this, msg.param(2)));
00522 bool received_first_names = channel->received_names();
00523
00524 std::string my_nick_name(msg.param(0));
00525 ASSERT(my_nick_name == mynick()->in_name(msg.server_session()));
00526
00527 msgout << prefix << msg.key() << mynick() << msg.param(1) << channel;
00528
00529 MsgPart names_list(msg.params(3));
00530 char const* list_start = names_list.start();
00531 if (*list_start == ':')
00532 ++list_start;
00533 char const* const list_end = names_list.end();
00534 char const* word_end;
00535 for (char const* word_start = list_start; word_start < list_end; word_start = word_end + 1)
00536 {
00537 ASSERT(*word_start != ' ');
00538 for (word_end = word_start; word_end < list_end && *word_end != ' '; ++word_end);
00539 std::string param(word_start, word_end - word_start);
00540 if (!IsNickChar(*word_start))
00541 {
00542 ASSERT(*word_start == '@' || *word_start == '+');
00543 std::string nick_name(word_start + 1, word_end - word_start - 1);
00544 boost::shared_ptr<Nick> nick;
00545 if (received_first_names)
00546 nick = Target::get_joined_nick(*this, nick_name, channel);
00547 else if (nick_name == my_nick_name)
00548 nick = mynick();
00549 else
00550 nick = Target::add_joined_nick(*this, nick_name, channel);
00551 msgout << *word_start << JustInTimeCatenate(nick);
00552 }
00553 else
00554 {
00555 std::string nick_name(word_start, word_end - word_start);
00556 boost::shared_ptr<Nick> nick;
00557 if (received_first_names)
00558 nick = Target::get_joined_nick(*this, nick_name, channel);
00559 else if (nick_name == my_nick_name)
00560 nick = mynick();
00561 else
00562 nick = Target::add_joined_nick(*this, nick_name, channel);
00563 msgout << nick;
00564 }
00565 }
00566 client_session().queue_msg(msgout);
00567 break;
00568 }
00569 case 366:
00570 {
00571
00572 Prefix prefix(msg);
00573
00574 MessageOut msgout(default_priority(msg.key()));
00575
00576 boost::shared_ptr<Channel> channel(Target::serverside_get_channel(*this, msg.param(1)));
00577 if (!channel->received_names())
00578 {
00579
00580 channel->set_received_names();
00581 }
00582
00583 ASSERT(msg.param(0) == mynick()->in_name(msg.server_session()));
00584
00585 client_session().queue_msg(msgout << prefix << msg.key() << mynick() << channel << msg.params(2));
00586 break;
00587 }
00588 case 433:
00589 server_session().nicks().inuse(msg.param(1));
00590 break;
00591 case 451:
00592 if (server_connection().state() == pong_sent)
00593 {
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603 server_session() << "QUIT\r\n" << std::flush;
00604 }
00605 break;
00606 case QUIT:
00607 do_quit(msg.prefix().get_nick(), msg.param(0));
00608 break;
00609 case NICK:
00610 {
00611 Prefix prefix(msg);
00612 Prefix old_prefix(prefix.out_prefix(client_session()));
00613 boost::shared_ptr<Nick> nick(prefix.get_nick());
00614 nick->serverside_nick_changed_to(msg.server_session(), msg.param(0));
00615
00616 nick->clientside_nick_changed_to(client_session(), msg.param(0));
00617
00618 MessageOut msgout(default_priority(msg.key()));
00619 client_session().queue_msg(msgout << old_prefix << msg.key() << nick);
00620 break;
00621 }
00622 case NOTICE:
00623 if (server_connection().state() <= pong_sent)
00624 break;
00625
00626 case PRIVMSG:
00627 {
00628 if (msg.params().empty())
00629 break;
00630 char c = *msg.params().front().start();
00631 if (c != '#' && c != '&' && c != '@')
00632 {
00633
00634
00635 ASSERT(c == '$' || msg.param(0) == server_session().nicks().in_nick() || (msg.key() == NOTICE && msg.param(0) == "*"));
00636
00637
00638 Prefix prefix(msg);
00639 MessageOut msgout(default_priority(msg.key()));
00640 if (c == '$' || msg.param(0) == "*")
00641 client_session().queue_msg(msgout << prefix << msg.key() << msg.params(0));
00642 else
00643 client_session().queue_msg(msgout << prefix << msg.key() << mynick() << msg.params(1));
00644 break;
00645 }
00646
00647 }
00648 case MODE:
00649 case PART:
00650 case KICK:
00651 case TOPIC:
00652 {
00653
00654
00655
00656 Target::serverside_get_channel(*this, msg.param(0), msg.key() == JOIN)->new_server_message_received(msg);
00657 break;
00658 }
00659 case JOIN:
00660 {
00661 Target::serverside_get_channel(*this, msg.param(0), msg.key() == JOIN)->new_server_message_received(msg);
00662 break;
00663 }
00664 default:
00665 Dout(dc::warning, "Unhandled command " << msg << " from server");
00666 pass_as_is_to_client(msg);
00667 break;
00668 }
00669 }
00670
00671
00672 void Identity::received_network_domain_answer(UserAnswerEventType const& event_type,
00673 std::pair<std::string, std::string> network_domain)
00674 {
00675 DoutEntering(dc::debug, "Identity::received_network_domain_answer(" << event_type);
00676 std::string answer = event_type.answer();
00677 bool yes = IRCStringCompare(answer, "Yes") == 0;
00678 bool no = IRCStringCompare(answer, "No") == 0;
00679 if (!yes && !no)
00680 {
00681 std::ostringstream the_question;
00682 the_question << "Does the " << network_domain.first << " IRC network use \"" <<
00683 network_domain.second << "\" as common domain for all servers (type: Yes|No)?";
00684 client_session().user_answer_event_server
00685 (UserAnswerRequestData(client_session(), network_domain_question, the_question.str()),
00686 *this, &Identity::received_network_domain_answer, network_domain);
00687 }
00688 else if (no)
00689 server_session().construct_network_object(network_domain.first, "");
00690 else
00691 server_session().construct_network_object(network_domain.first, network_domain.second);
00692 }
00693
00694 #if 0
00695
00696 std::string Identity::unique_target(char const* prefix) const
00697 {
00698 std::stringstream result;
00699 result << prefix;
00700 ClientSession::private_targets_type::const_iterator iter = client_session().private_targets().find(result.str());
00701 int postfix = 0;
00702 size_t len = strlen(prefix);
00703 while (iter != client_session().private_targets().end())
00704 {
00705 result.rdbuf()->pubseekpos(len);
00706 result << '.' << ++postfix;
00707 iter = client_session().private_targets().find(result.str());
00708 }
00709 return result.str();
00710 }
00711 #endif
00712
00713 boost::shared_ptr<Target> Identity::notice_target(question_nt number)
00714 {
00715 char const* channel_name;
00716
00717 if (number != no_related_question)
00718 {
00719 channel_name = question_target_name(number);
00720 ASSERT(is_channel(channel_name));
00721 }
00722
00723 while(1)
00724 {
00725 if (number == no_related_question)
00726 channel_name = "¬ices";
00727
00728 ClientSession::private_targets_type::iterator iter = client_session().private_targets().find(channel_name);
00729 if (iter != client_session().private_targets().end())
00730 return iter->second;
00731 if (number == no_related_question)
00732 break;
00733 number = no_related_question;
00734 }
00735
00736
00737 NoticeTarget* new_notice_target = new NoticeTarget(client_session(), channel_name, M_private_network);
00738 AllocTag(new_notice_target, channel_name);
00739
00740 boost::shared_ptr<Target> private_target(new_notice_target);
00741 client_session().add_private_target(private_target);
00742
00743 client_session() << ":" << client_session().client_out_nick() << " JOIN " << channel_name << "\r\n";
00744 new_notice_target->do_names_output();
00745
00746 return private_target;
00747 }
00748
00749
00750
00751
00752
00753 void Identity::send_notice(std::string const& notice, question_nt number)
00754 {
00755 *M_client_session << ":Leandro PRIVMSG " << notice_target(number)->out_name(*M_client_session) << " :" << notice << "\r\n";
00756 }
00757
00758
00759 std::string Identity::server_source(void) const
00760 {
00761 std::string result;
00762 if (M_primary_server_connection->has_server())
00763 result = M_primary_server_connection->server()->get_irc_name();
00764 if (result.empty())
00765 result = "ircproxy.net";
00766 return result;
00767 }
00768
00769
00770 void Identity::serialize(PersistXML& xml)
00771 {
00772 xml.serialize("M_key", M_key);
00773 xml.serialize("M_authpass", M_authpass);
00774 xml.serialize("M_network_name", M_network_name);
00775 }
00776
00777 Identity::~Identity()
00778 {
00779 Dout(dc::objects, "Destructing Identity " << *this << ".");
00780
00781 if (has_client_session())
00782 client_session().joined_channels().clear();
00783 if (has_server_session())
00784 server_session().joined_channels().clear();
00785 cancel_all_requests();
00786 }
00787