client_buffer.hpp

Go to the documentation of this file.
00001 /* libobby - Network text editing library
00002  * Copyright (C) 2005, 2006 0x539 dev group
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public
00015  * License along with this program; if not, write to the Free
00016  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 #ifndef _OBBY_CLIENT_BUFFER_HPP_
00020 #define _OBBY_CLIENT_BUFFER_HPP_
00021 
00022 #include <net6/default_accumulator.hpp>
00023 #include <net6/client.hpp>
00024 #include "error.hpp"
00025 #include "command.hpp"
00026 #include "local_buffer.hpp"
00027 #include "client_document_info.hpp"
00028 
00029 namespace obby
00030 {
00031 
00034 template<typename Document, typename Selector>
00035 class basic_client_buffer:
00036         virtual public basic_local_buffer<Document, Selector>
00037 {
00038 public:
00039         struct connection_settings {
00040                 std::string name;
00041                 obby::colour colour;
00042                 std::string global_password;
00043                 std::string user_password;
00044         };
00045 
00046         // Document info
00047         typedef typename basic_local_buffer<Document, Selector>::
00048 		base_document_info_type base_document_info_type;
00049 
00050         typedef basic_client_document_info<Document, Selector>
00051                 document_info_type;
00052 
00053         // Network
00054         typedef typename basic_local_buffer<Document, Selector>::
00055 		base_net_type base_net_type;
00056 
00057         typedef net6::basic_client<Selector> net_type;
00058 
00059         // Signal
00060         typedef net6::default_accumulator<bool, false> login_accumulator;
00061 
00062         typedef sigc::signal<void>
00063                 signal_welcome_type;
00064         typedef sigc::signal<void, login::error>
00065                 signal_login_failed_type;
00066         typedef sigc::signal<void>
00067                 signal_close_type;
00068 
00069         typedef typename sigc::signal<bool, connection_settings&>
00070                 ::template accumulated<login_accumulator>
00071                 signal_prompt_name_type;
00072         typedef typename sigc::signal<bool, connection_settings&>
00073                 ::template accumulated<login_accumulator>
00074                 signal_prompt_colour_type;
00075         typedef typename sigc::signal<bool, connection_settings&>
00076                 ::template accumulated<login_accumulator>
00077                 signal_prompt_global_password_type;
00078         typedef typename sigc::signal<bool, connection_settings&>
00079                 ::template accumulated<login_accumulator>
00080                 signal_prompt_user_password_type;
00081 
00084         basic_client_buffer();
00085 
00098         void connect(const std::string& hostname, unsigned int port = 6522);
00099 
00105         void disconnect();
00106 
00109         //bool is_connected() const;
00110 
00113         //void request_encryption();
00114 
00126         void login(const std::string& name,
00127                    const obby::colour& colour);
00128 
00131         bool is_logged_in() const;
00132 
00137         virtual void document_create(const std::string& title,
00138                                      const std::string& encoding,
00139                                      const std::string& content = "");
00140 
00145         virtual void document_remove(base_document_info_type& doc);
00146 
00152         document_info_type* document_find(unsigned int owner_id,
00153                                           unsigned int id) const;
00154 
00157         virtual const user& get_self() const;
00158 
00162         virtual const std::string& get_name() const;
00163 
00166         virtual void send_message(const std::string& message);
00167 
00170         virtual void send_command(const command_query& query);
00171 
00174         virtual void set_password(const std::string& password);
00175 
00178         virtual void set_colour(const colour& colour);
00179 
00186         void set_enable_keepalives(bool enable);
00187 
00193         signal_welcome_type welcome_event() const;
00194 
00198         signal_close_type close_event() const;
00199 
00202         signal_login_failed_type login_failed_event() const;
00203 
00206         signal_prompt_name_type prompt_name_event() const;
00207 
00210         signal_prompt_colour_type prompt_colour_event() const;
00211 
00214         signal_prompt_global_password_type prompt_global_password_event() const;
00215 
00218         signal_prompt_user_password_type prompt_user_password_event() const;
00219 
00220 protected:
00224         void register_signal_handlers();
00225 
00228         virtual base_document_info_type*
00229         new_document_info(const user* owner,
00230                           unsigned int id,
00231                           const std::string& title,
00232                           unsigned int suffix,
00233                           const std::string& encoding);
00234 
00237         virtual base_document_info_type*
00238         new_document_info(const user* owner,
00239                           unsigned int id,
00240                           const std::string& title,
00241                           const std::string& encoding,
00242                           const std::string& content);
00243 
00246         virtual base_document_info_type*
00247         new_document_info(const net6::packet& pack);
00248 
00254         virtual base_net_type* new_net();
00255 
00258         void on_join(const net6::user& user6, const net6::packet& pack);
00259         void on_part(const net6::user& user6, const net6::packet& pack);
00260         void on_close();
00261         void on_encrypted();
00262         void on_data(const net6::packet& pack);
00263         void on_login_failed(net6::login::error error);
00264         void on_login_extend(net6::packet& pack);
00265 
00268         virtual bool execute_packet(const net6::packet& pack);
00269 
00272         virtual void on_net_welcome(const net6::packet& pack);
00273 
00276         virtual void on_net_document_create(const net6::packet& pack);
00277         virtual void on_net_document_remove(const net6::packet& pack);
00278 
00281         virtual void on_net_message(const net6::packet& pack);
00282         virtual void on_net_emote_message(const net6::packet& pack);
00283 
00286         virtual void on_net_user_colour(const net6::packet& pack);
00287         virtual void on_net_user_colour_failed(const net6::packet& pack);
00288 
00291         virtual void on_net_sync_init(const net6::packet& pack);
00292         virtual void on_net_sync_usertable_user(const net6::packet& pack);
00293         virtual void on_net_sync_doclist_document(const net6::packet& pack);
00294         virtual void on_net_sync_final(const net6::packet& pack);
00295 
00298         virtual void on_net_document(const net6::packet& pack);
00299 
00302         virtual void on_net_command_result(const net6::packet& pack);
00303 
00304         void on_command_emote(const command_query& query,
00305                               const command_result& result);
00306 
00309         virtual void session_close();
00310 
00314         void session_close_impl();
00315 
00316         const user* m_self;
00317 
00318         connection_settings m_settings;
00319         bool m_enable_keepalives;
00320 
00321         signal_welcome_type m_signal_welcome;
00322         signal_close_type m_signal_close;
00323         signal_login_failed_type m_signal_login_failed;
00324 
00325         signal_prompt_name_type m_signal_prompt_name;
00326         signal_prompt_colour_type m_signal_prompt_colour;
00327         signal_prompt_global_password_type m_signal_prompt_global_password;
00328         signal_prompt_user_password_type m_signal_prompt_user_password;
00329 private:
00333         net_type& net6_client();
00334 
00338         const net_type& net6_client() const;
00339 };
00340 
00341 typedef basic_client_buffer<obby::document, net6::selector> client_buffer;
00342 
00343 template<typename Document, typename Selector>
00344 basic_client_buffer<Document, Selector>::basic_client_buffer():
00345         basic_local_buffer<Document, Selector>(), m_self(NULL),
00346         m_enable_keepalives(false)
00347 {
00348         const command_queue& queue =
00349                 basic_local_buffer<Document, Selector>::m_command_queue;
00350 
00351         queue.result_event("me").connect(
00352                 sigc::mem_fun(*this, &basic_client_buffer::on_command_emote)
00353         );
00354 }
00355 
00356 template<typename Document, typename Selector>
00357 void basic_client_buffer<Document, Selector>::
00358 	connect(const std::string& hostname,
00359                 unsigned int port)
00360 {
00361         if(basic_buffer<Document, Selector>::is_open() )
00362         {
00363                 throw std::logic_error(
00364                         "obby::basic_client_buffer::connect:\n"
00365                         "Connection already established"
00366                 );
00367         }
00368 
00369         // Create connection object
00370         basic_buffer<Document, Selector>::m_net.reset(new_net() );
00371 
00372         // Register signal handlers
00373         register_signal_handlers();
00374 
00375         // Make sure that the signal handlers to the net6::client object
00376         // are registered before the connection is made, otherwise we may
00377         // lose a welcome packet if the remote site sends the packet between
00378         // the connection and the signal handler registration (which _may_
00379         // occur with connections to localhost).
00380         try
00381         {
00382                 net6_client().connect(
00383                         net6::ipv4_address::create_from_hostname(
00384                                 hostname,
00385                                 port
00386                         )
00387                 );
00388         }
00389         catch(net6::error& e)
00390         {
00391                 if(!IPV6_ENABLED) throw e;
00392 
00393                 net6_client().connect(
00394                         net6::ipv6_address::create_from_hostname(
00395                                 hostname,
00396                                 port
00397                         )
00398                 );
00399         }
00400 
00401         net6_client().set_enable_keepalives(m_enable_keepalives);
00402 }
00403 
00404 template<typename Document, typename Selector>
00405 void basic_client_buffer<Document, Selector>::disconnect()
00406 {
00407         if(!basic_buffer<Document, Selector>::is_open() )
00408         {
00409                 throw std::logic_error(
00410                         "obby::basic_client_buffer::disconnect:\n"
00411                         "Client is not connected"
00412                 );
00413         }
00414 
00415         // Close session
00416         session_close();
00417 }
00418 
00419 template<typename Document, typename Selector>
00420 void basic_client_buffer<Document, Selector>::login(const std::string& name,
00421                                                     const colour& colour)
00422 {
00423         m_settings.name = name;
00424         m_settings.colour = colour;
00425 
00426         net6_client().login(name);
00427 }
00428 
00429 template<typename Document, typename Selector>
00430 bool basic_client_buffer<Document, Selector>::is_logged_in() const
00431 {
00432         // TODO: Return true or false when being disconnected and still
00433         // having an old session?
00434         //
00435         // Some functions like document_remove depend on the current
00436         // behavior. Change them accordingly if you change something here!
00437         if(basic_buffer<Document, Selector>::m_net.get() == NULL) return false;
00438         return net6_client().is_logged_in();
00439 }
00440 
00441 template<typename Document, typename Selector>
00442 void basic_client_buffer<Document, Selector>::
00443 	document_create(const std::string& title,
00444                         const std::string& encoding,
00445                         const std::string& content)
00446 {
00447         // TODO: Allow this and create the document just locally?
00448         if(!is_logged_in() )
00449         {
00450                 throw std::logic_error(
00451                         "obby::basic_client_buffer::document_create:\n"
00452                         "Cannot create document without being logged in"
00453                 );
00454         }
00455 
00456         // TODO: m_doc_counter does not belong into the base class
00457         unsigned int id = ++ basic_buffer<Document, Selector>::m_doc_counter;
00458         // Create document
00459         base_document_info_type* info =
00460                 new_document_info(m_self, id, title, encoding, content);
00461         // Add document to list
00462         basic_buffer<Document, Selector>::document_add(*info);
00463         // Tell server
00464         net6::packet request_pack("obby_document_create");
00465         request_pack << id << title << encoding << content;
00466         net6_client().send(request_pack);
00467 }
00468 
00469 template<typename Document, typename Selector>
00470 void basic_client_buffer<Document, Selector>::
00471 	document_remove(base_document_info_type& document)
00472 {
00473         if(is_logged_in() )
00474         {
00475                 // Send remove request, remove document on server reply
00476                 // to ensure synchronisation
00477                 net6::packet request_pack("obby_document_remove");
00478                 request_pack << &document;
00479                 net6_client().send(request_pack);
00480         }
00481         else
00482         {
00483                 // Delete document
00484                 basic_buffer<Document, Selector>::document_delete(document);
00485         }
00486 }
00487 
00488 template<typename Document, typename Selector>
00489 typename basic_client_buffer<Document, Selector>::document_info_type*
00490 basic_client_buffer<Document, Selector>::
00491 	document_find(unsigned int owner_id,
00492                       unsigned int id) const
00493 {
00494         return dynamic_cast<document_info_type*>(
00495                 basic_buffer<Document, Selector>::document_find(owner_id, id)
00496         );
00497 }
00498 
00499 template<typename Document, typename Selector>
00500 const obby::user& basic_client_buffer<Document, Selector>::get_self() const
00501 {
00502         if(m_self == NULL)
00503         {
00504                 throw std::logic_error(
00505                         "obby::basic_client_buffer::get_self:\n"
00506                         "Client is not logged in"
00507                 );
00508         }
00509 
00510         return *m_self;
00511 }
00512 
00513 template<typename Document, typename Selector>
00514 const std::string& basic_client_buffer<Document, Selector>::get_name() const
00515 {
00516         // TODO: Do we still need this?
00517         if(m_self == NULL) return m_settings.name;
00518         return basic_local_buffer<Document, Selector>::get_name();
00519 }
00520 
00521 template<typename Document, typename Selector>
00522 void basic_client_buffer<Document, Selector>::
00523 	send_message(const std::string& message)
00524 {
00525         if(is_logged_in() )
00526         {
00527                 // Wait for server response to ensure synchronisation
00528                 net6::packet message_pack("obby_message");
00529                 message_pack << message;
00530                 net6_client().send(message_pack);
00531         }
00532         else
00533         {
00534                 // If we have never been connected to a session we have no
00535                 // user that might send this message
00536                 if(m_self == NULL)
00537                 {
00538                         throw std::logic_error(
00539                                 "obby::basic_client_buffer::send_message:\n"
00540                                 "No self user available. Probably the client "
00541                                 "buffer never has been connected to a session."
00542                         );
00543                 }
00544 
00545                 basic_buffer<Document, Selector>::m_chat.add_user_message(
00546                         message, get_self()
00547                 );
00548         }
00549 }
00550 
00551 template<typename Document, typename Selector>
00552 void basic_client_buffer<Document, Selector>::
00553 	send_command(const command_query& query)
00554 {
00555         if(!is_logged_in() )
00556         {
00557                 throw std::logic_error(
00558                         "obby::basic_client_buffer::send_command:\n"
00559                         "Cannot send command without being logged in"
00560                 );
00561         }
00562 
00563         basic_local_buffer<Document, Selector>::m_command_queue.query(query);
00564 
00565         net6::packet pack("obby_command_query");
00566         query.append_packet(pack);
00567 
00568         net6_client().send(pack);
00569 }
00570 
00571 template<typename Document, typename Selector>
00572 void basic_client_buffer<Document, Selector>::
00573 	set_password(const std::string& password)
00574 {
00575         if(is_logged_in() )
00576         {
00577                 net6::packet password_pack("obby_user_password");
00578                 password_pack << password;
00579                 net6_client().send(password_pack);
00580         }
00581         else
00582         {
00583                 throw std::logic_error(
00584                         "obby::basic_client_buffer::set_password:\n"
00585                         "Cannot set password without being logged in"
00586                 );
00587         }
00588 }
00589 
00590 template<typename Document, typename Selector>
00591 void basic_client_buffer<Document, Selector>::set_colour(const colour& colour)
00592 {
00593         if(is_logged_in() )
00594         {
00595                 net6::packet colour_pack("obby_user_colour");
00596                 colour_pack << colour;
00597                 net6_client().send(colour_pack);
00598         }
00599         else
00600         {
00601                 throw std::logic_error(
00602                         "obby::basic_client_buffer::::set_colour:\n"
00603                         "Cannot change colour without being logged in"
00604                 );
00605         }
00606 }
00607 
00608 template<typename Document, typename Selector>
00609 void basic_client_buffer<Document, Selector>::set_enable_keepalives(bool enable)
00610 {
00611         if(m_enable_keepalives == enable) return;
00612 
00613         m_enable_keepalives = enable;
00614         if(basic_buffer<Document, Selector>::m_net.get() != NULL)
00615                 net6_client().set_enable_keepalives(enable);
00616 }
00617 
00618 template<typename Document, typename Selector>
00619 typename basic_client_buffer<Document, Selector>::signal_welcome_type
00620 basic_client_buffer<Document, Selector>::welcome_event() const
00621 {
00622         return m_signal_welcome;
00623 }
00624 
00625 template<typename Document, typename Selector>
00626 typename basic_client_buffer<Document, Selector>::signal_login_failed_type
00627 basic_client_buffer<Document, Selector>::login_failed_event() const
00628 {
00629         return m_signal_login_failed;
00630 }
00631 
00632 template<typename Document, typename Selector>
00633 typename basic_client_buffer<Document, Selector>::signal_prompt_name_type
00634 basic_client_buffer<Document, Selector>::prompt_name_event() const
00635 {
00636         return m_signal_prompt_name;
00637 }
00638 
00639 template<typename Document, typename Selector>
00640 typename basic_client_buffer<Document, Selector>::signal_prompt_colour_type
00641 basic_client_buffer<Document, Selector>::prompt_colour_event() const
00642 {
00643         return m_signal_prompt_colour;
00644 }
00645 
00646 template<typename Document, typename Selector>
00647 typename basic_client_buffer<Document, Selector>::
00648         signal_prompt_global_password_type
00649 basic_client_buffer<Document, Selector>::prompt_global_password_event() const
00650 {
00651         return m_signal_prompt_global_password;
00652 }
00653 
00654 template<typename Document, typename Selector>
00655 typename basic_client_buffer<Document, Selector>::
00656         signal_prompt_user_password_type
00657 basic_client_buffer<Document, Selector>::prompt_user_password_event() const
00658 {
00659         return m_signal_prompt_user_password;
00660 }
00661 
00662 template<typename Document, typename Selector>
00663 typename basic_client_buffer<Document, Selector>::signal_close_type
00664 basic_client_buffer<Document, Selector>::close_event() const
00665 {
00666         return m_signal_close;
00667 }
00668 
00669 template<typename Document, typename Selector>
00670 void basic_client_buffer<Document, Selector>::on_join(const net6::user& user6,
00671                                                       const net6::packet& pack)
00672 {
00673         unsigned int id =
00674                 pack.get_param(3).net6::parameter::as<unsigned int>();
00675         colour colour =
00676                 pack.get_param(4).net6::parameter::as<obby::colour>();
00677 
00678         // Add user
00679         const user* new_user = basic_buffer<Document, Selector>::
00680 		m_user_table.add_user(id, user6, colour);
00681 
00682         // The first joining user is the local one
00683         if(m_self == NULL) m_self = new_user;
00684 
00685         basic_buffer<Document, Selector>::user_join(*new_user);
00686 }
00687 
00688 template<typename Document, typename Selector>
00689 void basic_client_buffer<Document, Selector>::on_part(const net6::user& user6,
00690                                                       const net6::packet& pack)
00691 {
00692         // Find user
00693         const user* cur_user =
00694                 basic_buffer<Document, Selector>::m_user_table.find(
00695                         user6,
00696                         user::flags::CONNECTED,
00697                         user::flags::NONE
00698                 );
00699 
00700         // Should never happen
00701         if(cur_user == NULL)
00702         {
00703                 format_string str("User %0% is not connected");
00704                 str << user6.get_id();
00705                 throw net6::bad_value(str.str() );
00706         }
00707 
00708         basic_buffer<Document, Selector>::user_part(*cur_user);
00709 }
00710 
00711 template<typename Document, typename Selector>
00712 void basic_client_buffer<Document, Selector>::on_close()
00713 {
00714         // Disconnect
00715         disconnect();
00716         // TODO: Emit signal_close in the disconnect() function?
00717         m_signal_close.emit();
00718 }
00719 
00720 template<typename Document, typename Selector>
00721 void basic_client_buffer<Document, Selector>::on_encrypted()
00722 {
00723         // Login now possible
00724         m_signal_welcome.emit();
00725 }
00726 
00727 template<typename Document, typename Selector>
00728 void basic_client_buffer<Document, Selector>::on_data(const net6::packet& pack)
00729 {
00730         if(!execute_packet(pack) )
00731         {
00732                 throw net6::bad_value(
00733                         "Unexpected command: " + pack.get_command()
00734                 );
00735         }
00736 }
00737 
00738 template<typename Document, typename Selector>
00739 void basic_client_buffer<Document, Selector>::
00740 	on_login_failed(net6::login::error error)
00741 {
00742         if(error == net6::login::ERROR_NAME_IN_USE)
00743         {
00744                 if(m_signal_prompt_name.emit(m_settings) )
00745                         login(m_settings.name, m_settings.colour);
00746         }
00747         else if(error == login::ERROR_COLOUR_IN_USE)
00748         {
00749                 if(m_signal_prompt_colour.emit(m_settings) )
00750                         login(m_settings.name, m_settings.colour);
00751         }
00752         else if(error == login::ERROR_WRONG_GLOBAL_PASSWORD)
00753         {
00754                 if(m_signal_prompt_global_password.emit(m_settings) )
00755                         login(m_settings.name, m_settings.colour);
00756         }
00757         else if(error == login::ERROR_WRONG_USER_PASSWORD)
00758         {
00759                 if(m_signal_prompt_user_password.emit(m_settings) )
00760                         login(m_settings.name, m_settings.colour);
00761         }
00762         else
00763         {
00764                 m_signal_login_failed.emit(error);
00765         }
00766 }
00767 
00768 template<typename Document, typename Selector>
00769 void basic_client_buffer<Document, Selector>::
00770 	on_login_extend(net6::packet& pack)
00771 {
00772         // Add user colour and, if given, (hashed) passwords.
00773         pack << m_settings.colour;
00774         if(!m_settings.global_password.empty() ||
00775            !m_settings.user_password.empty() )
00776         {
00777                 pack << m_settings.global_password;
00778                 if(!m_settings.user_password.empty() )
00779                         pack << m_settings.user_password;
00780         }
00781 }
00782 
00783 template<typename Document, typename Selector>
00784 bool basic_client_buffer<Document, Selector>::
00785 	execute_packet(const net6::packet& pack)
00786 {
00787         // TODO: std::map<> from command to function
00788         if(pack.get_command() == "obby_welcome")
00789                 { on_net_welcome(pack); return true; }
00790 
00791         if(pack.get_command() == "obby_document_create")
00792                 { on_net_document_create(pack); return true; }
00793 
00794         if(pack.get_command() == "obby_document_remove")
00795                 { on_net_document_remove(pack); return true; }
00796 
00797         if(pack.get_command() == "obby_message")
00798                 { on_net_message(pack); return true; }
00799 
00800         if(pack.get_command() == "obby_emote_message")
00801                 { on_net_emote_message(pack); return true; }
00802 
00803         if(pack.get_command() == "obby_user_colour")
00804                 { on_net_user_colour(pack); return true; }
00805 
00806         if(pack.get_command() == "obby_user_colour_failed")
00807                 { on_net_user_colour_failed(pack); return true; }
00808 
00809         if(pack.get_command() == "obby_sync_init")
00810                 { on_net_sync_init(pack); return true; }
00811 
00812         if(pack.get_command() == "obby_sync_usertable_user")
00813                 { on_net_sync_usertable_user(pack); return true; }
00814 
00815         if(pack.get_command() == "obby_sync_doclist_document")
00816                 { on_net_sync_doclist_document(pack); return true; }
00817 
00818         if(pack.get_command() == "obby_sync_final")
00819                 { on_net_sync_final(pack); return true; }
00820 
00821         if(pack.get_command() == "obby_document")
00822                 { on_net_document(pack); return true; }
00823 
00824         if(pack.get_command() == "obby_command_result")
00825                 { on_net_command_result(pack); return true; }
00826 
00827         return false;
00828 }
00829 
00830 template<typename Document, typename Selector>
00831 void basic_client_buffer<Document, Selector>::
00832 	on_net_welcome(const net6::packet& pack)
00833 {
00834         // Get the OBBY version the server is running and compare to the
00835         // version of this library.
00836         unsigned long server_version =
00837                 pack.get_param(0).net6::parameter::as<unsigned long>();
00838 
00839         if(server_version != PROTOCOL_VERSION)
00840         {
00841                 on_login_failed(login::ERROR_PROTOCOL_VERSION_MISMATCH);
00842                 return;
00843         }
00844 
00845         // Emit welcome signal to indicate that the user may now perform a
00846         // login() call.
00847         //
00848         // Do no longer emit signal welcome here since the login has to be
00849         // performed after the connection has been encrypted since
00850         // obby 0.4.0.
00851         //m_signal_welcome.emit();
00852 }
00853 
00854 template<typename Document, typename Selector>
00855 void basic_client_buffer<Document, Selector>::
00856 	on_net_document_create(const net6::packet& pack)
00857 {
00858         // Get owner, id and title
00859         const user* owner = pack.get_param(0).net6::parameter::as<const user*>(
00860                 ::serialise::hex_context_from<const user*>(
00861                         basic_buffer<Document, Selector>::get_user_table()
00862                 )
00863         );
00864 
00865         unsigned int id =
00866                 pack.get_param(1).net6::parameter::as<unsigned int>();
00867         const std::string& title =
00868                 pack.get_param(2).net6::parameter::as<std::string>();
00869         unsigned int suffix =
00870                 pack.get_param(3).net6::parameter::as<unsigned int>();
00871         const std::string& encoding =
00872                 pack.get_param(4).net6::parameter::as<std::string>();
00873 
00874         // Get owner ID
00875         unsigned int owner_id = (owner == NULL ? 0 : owner->get_id() );
00876 
00877         // Document owner must not be the local user because if we created the
00878         // document, the create_document request is not sent back to us.
00879         if(owner == m_self)
00880         {
00881                 format_string str("Owner of document %0%/%1% is self");
00882                 str << owner_id << id;
00883                 throw net6::bad_value(str.str() );
00884         }
00885 
00886         // Is there already such a document?
00887         if(document_find(owner_id, id) )
00888         {
00889                 format_string str("Document %0%/%1% exists already");
00890                 str << owner_id << id;
00891                 throw net6::bad_value(str.str() );
00892         }
00893 
00894         // Add new document
00895         base_document_info_type* info =
00896                 new_document_info(owner, id, title, suffix, encoding);
00897 
00898                 basic_buffer<Document, Selector>::document_add(*info);
00899 }
00900 
00901 template<typename Document, typename Selector>
00902 void basic_client_buffer<Document, Selector>::
00903 	on_net_document_remove(const net6::packet& pack)
00904 {
00905         // Get document to remove
00906         document_info_type& doc = dynamic_cast<document_info_type&>(
00907                 *pack.get_param(0).net6::parameter::as<
00908                         base_document_info_type*
00909                 >(::serialise::hex_context_from<base_document_info_type*>(
00910                         *this
00911                 ))
00912         );
00913 
00914         // Emit unsubscribe singal for users who were subscribed to this doc
00915         // TODO: Do this is in document_delete!
00916         for(typename document_info_type::user_iterator user_iter =
00917                 doc.user_begin();
00918             user_iter != doc.user_end();
00919             ++ user_iter)
00920         {
00921                 doc.unsubscribe_event().emit(*user_iter);
00922         }
00923 
00924         // Delete document
00925         basic_buffer<Document, Selector>::document_delete(doc);
00926 }
00927 
00928 template<typename Document, typename Selector>
00929 void basic_client_buffer<Document, Selector>::
00930 	on_net_message(const net6::packet& pack)
00931 {
00932         const user* writer = pack.get_param(0).net6::parameter::as<const user*>(
00933                 ::serialise::hex_context_from<const user*>(
00934                         basic_buffer<Document, Selector>::get_user_table()
00935                 )
00936         );
00937 
00938         const std::string& message =
00939                 pack.get_param(1).net6::parameter::as<std::string>();
00940 
00941         // Valid user id indicates that the message comes from a user, otherwise
00942         // the server sent the message directly
00943         if(writer != NULL)
00944         {
00945                 basic_buffer<Document, Selector>::m_chat.add_user_message(
00946                         message,
00947                         *writer
00948                 );
00949         }
00950         else
00951         {
00952                 basic_buffer<Document, Selector>::m_chat.add_server_message(
00953                         message
00954                 );
00955         }
00956 }
00957 
00958 template<typename Document, typename Selector>
00959 void basic_client_buffer<Document, Selector>::
00960 	on_net_emote_message(const net6::packet& pack)
00961 {
00962         const user* writer = pack.get_param(0).net6::parameter::as<const user*>(
00963                 ::serialise::hex_context_from<const user*>(
00964                         basic_buffer<Document, Selector>::get_user_table()
00965                 )
00966         );
00967 
00968         const std::string& message =
00969                 pack.get_param(1).net6::parameter::as<std::string>();
00970 
00971         if(writer == NULL)
00972         {
00973                 throw std::logic_error(
00974                         "obby::basic_client_buffer::on_net_emote_message:\n"
00975                         "Server cannot send emote messages"
00976                 );
00977         }
00978 
00979         basic_buffer<Document, Selector>::m_chat.add_emote_message(
00980                 message,
00981                 *writer
00982         );
00983 }
00984 
00985 template<typename Document, typename Selector>
00986 void basic_client_buffer<Document, Selector>::
00987 	on_net_user_colour(const net6::packet& pack)
00988 {
00989         const user* from = pack.get_param(0).net6::parameter::as<const user*>(
00990                 ::serialise::hex_context_from<const user*>(
00991                         basic_buffer<Document, Selector>::get_user_table()
00992                 )
00993         );
00994 
00995         basic_buffer<Document, Selector>::m_user_table.set_user_colour(
00996                 *from,
00997                 pack.get_param(1).net6::parameter::as<obby::colour>()
00998         );
00999 
01000         // TODO: user::set_colour should emit the signal
01001         basic_buffer<Document, Selector>::m_signal_user_colour.emit(*from);
01002 }
01003 
01004 template<typename Document, typename Selector>
01005 void basic_client_buffer<Document, Selector>::
01006 	on_net_user_colour_failed(const net6::packet& pack)
01007 {
01008         basic_local_buffer<Document, Selector>::
01009 		m_signal_user_colour_failed.emit();
01010 }
01011 
01012 template<typename Document, typename Selector>
01013 void basic_client_buffer<Document, Selector>::
01014 	on_net_sync_init(const net6::packet& pack)
01015 {
01016         // Login was successful, synchronisation begins. Clear users and
01017         // documents from old session that have been kept to be able to still
01018         // access them while being disconnected.
01019         basic_buffer<Document, Selector>::m_user_table.clear();
01020         basic_buffer<Document, Selector>::document_clear();
01021         m_self = NULL;
01022 
01023         basic_buffer<Document, Selector>::m_signal_sync_init.emit(
01024                 pack.get_param(0).net6::parameter::as<unsigned int>()
01025         );
01026 }
01027 
01028 template<typename Document, typename Selector>
01029 void basic_client_buffer<Document, Selector>::
01030 	on_net_sync_usertable_user(const net6::packet& pack)
01031 {
01032         // User that was already in the obby session, but isn't anymore.
01033 
01034         // Extract data from packet
01035         unsigned int id =
01036                 pack.get_param(0).net6::parameter::as<unsigned int>();
01037         const std::string& name =
01038                 pack.get_param(1).net6::parameter::as<std::string>();
01039         colour colour =
01040                 pack.get_param(2).net6::parameter::as<obby::colour>();
01041 
01042         // Add user into user table
01043         basic_buffer<Document, Selector>::m_user_table.add_user(
01044                 id, name, colour
01045         );
01046 
01047         // TODO: Emit user_join_signal. Should be done automatically by the
01048         // function call above
01049 }
01050 
01051 template<typename Document, typename Selector>
01052 void basic_client_buffer<Document, Selector>::
01053 	on_net_sync_doclist_document(const net6::packet& pack)
01054 {
01055         // Get data from packet
01056         const user* owner = pack.get_param(0).net6::parameter::as<const user*>(
01057                 ::serialise::hex_context_from<const user*>(
01058                         basic_buffer<Document, Selector>::get_user_table()
01059                 )
01060         );
01061 
01062         unsigned int id =
01063                 pack.get_param(1).net6::parameter::as<unsigned int>();
01064 
01065         // Get document owner ID
01066         unsigned int owner_id = (owner == NULL ? 0 : owner->get_id() );
01067 
01068         // Initialise document counter to the document's ID to produce
01069         // unique IDs even when rejoining a session.
01070         if(owner_id == m_self->get_id() &&
01071            id >= basic_buffer<Document, Selector>::m_doc_counter)
01072         {
01073                 basic_buffer<Document, Selector>::m_doc_counter = id + 1;
01074         }
01075 
01076         // Check for duplicates, should not happen
01077         if(document_find(owner_id, id) != NULL)
01078         {
01079                 format_string str("Document %0%/%1% exists already");
01080                 str << owner_id << id;
01081                 throw net6::bad_value(str.str() );
01082         }
01083 
01084         // Create document_info from packet
01085         base_document_info_type* info = new_document_info(pack);
01086         // Add to buffer
01087         basic_buffer<Document, Selector>::document_add(*info);
01088 }
01089 
01090 template<typename Document, typename Selector>
01091 void basic_client_buffer<Document, Selector>::
01092 	on_net_sync_final(const net6::packet& pack)
01093 {
01094         basic_buffer<Document, Selector>::m_signal_sync_final.emit();
01095 }
01096 
01097 template<typename Document, typename Selector>
01098 void basic_client_buffer<Document, Selector>::
01099 	on_net_document(const net6::packet& pack)
01100 {
01101         // Get document, forward packet
01102         document_info_type& info = dynamic_cast<document_info_type&>(
01103                 *pack.get_param(0).net6::parameter::as<
01104                         base_document_info_type*
01105                 >(::serialise::hex_context_from<base_document_info_type*>(
01106                         *this
01107                 ))
01108         );
01109 
01110         // TODO: Rename this function. Think about providing a signal that may
01111         // be emitted.
01112         info.on_net_packet(document_packet(pack) );
01113 }
01114 
01115 template<typename Document, typename Selector>
01116 void basic_client_buffer<Document, Selector>::
01117 	on_net_command_result(const net6::packet& pack)
01118 {
01119         unsigned int index = 0;
01120         command_result result(pack, index);
01121 
01122         basic_local_buffer<Document, Selector>::m_command_queue.result(result);
01123 }
01124 
01125 template<typename Document, typename Selector>
01126 void basic_client_buffer<Document, Selector>::
01127 	on_command_emote(const command_query& query,
01128                          const command_result& result)
01129 {
01130         basic_buffer<Document, Selector>::m_chat.add_emote_message(
01131                 query.get_paramlist(),
01132                 *m_self
01133         );
01134 }
01135 
01136 template<typename Document, typename Selector>
01137 void basic_client_buffer<Document, Selector>::session_close()
01138 {
01139         session_close_impl();
01140         basic_local_buffer<Document, Selector>::session_close_impl();
01141         basic_buffer<Document, Selector>::session_close_impl();
01142 }
01143 
01144 template<typename Document, typename Selector>
01145 void basic_client_buffer<Document, Selector>::session_close_impl()
01146 {
01147         // Reset passwords to prevent using them for the next connection
01148         m_settings.global_password = m_settings.user_password = "";
01149 }
01150 
01151 template<typename Document, typename Selector>
01152 void basic_client_buffer<Document, Selector>::register_signal_handlers()
01153 {
01154         net6_client().join_event().connect(
01155                 sigc::mem_fun(*this, &basic_client_buffer::on_join) );
01156         net6_client().part_event().connect(
01157                 sigc::mem_fun(*this, &basic_client_buffer::on_part) );
01158         net6_client().close_event().connect(
01159                 sigc::mem_fun(*this, &basic_client_buffer::on_close) );
01160         net6_client().encrypted_event().connect(
01161                 sigc::mem_fun(*this, &basic_client_buffer::on_encrypted) );
01162         net6_client().data_event().connect(
01163                 sigc::mem_fun(*this, &basic_client_buffer::on_data) );
01164         net6_client().login_failed_event().connect(
01165                 sigc::mem_fun(*this, &basic_client_buffer::on_login_failed) );
01166         net6_client().login_extend_event().connect(
01167                 sigc::mem_fun(*this, &basic_client_buffer::on_login_extend) );
01168 }
01169 
01170 template<typename Document, typename Selector>
01171 typename basic_client_buffer<Document, Selector>::base_document_info_type*
01172 basic_client_buffer<Document, Selector>::
01173 	new_document_info(const user* owner,
01174                           unsigned int id,
01175                           const std::string& title,
01176                           unsigned int suffix,
01177                           const std::string& encoding)
01178 {
01179         // Create client_document_info, according to client_buffer
01180         return new document_info_type(
01181                 *this, net6_client(), owner, id, title, suffix, encoding
01182         );
01183 }
01184 
01185 template<typename Document, typename Selector>
01186 typename basic_client_buffer<Document, Selector>::base_document_info_type*
01187 basic_client_buffer<Document, Selector>::
01188 	new_document_info(const user* owner,
01189                           unsigned int id,
01190                           const std::string& title,
01191                           const std::string& encoding,
01192                           const std::string& content)
01193 {
01194         return new document_info_type(
01195                 *this, net6_client(), owner, id, title, encoding, content
01196         );
01197 }
01198 
01199 template<typename Document, typename Selector>
01200 typename basic_client_buffer<Document, Selector>::base_document_info_type*
01201 basic_client_buffer<Document, Selector>::
01202 	new_document_info(const net6::packet& pack)
01203 {
01204         return new document_info_type(*this, net6_client(), pack);
01205 }
01206 
01207 template<typename Document, typename Selector>
01208 typename basic_client_buffer<Document, Selector>::base_net_type*
01209 basic_client_buffer<Document, Selector>::new_net()
01210 {
01211         // Connect to remote host
01212         return new net_type;
01213 }
01214 
01215 template<typename Document, typename Selector>
01216 typename basic_client_buffer<Document, Selector>::net_type&
01217 basic_client_buffer<Document, Selector>::net6_client()
01218 {
01219         return dynamic_cast<net_type&>(
01220                 *basic_buffer<Document, Selector>::m_net.get()
01221         );
01222 }
01223 
01224 template<typename Document, typename Selector>
01225 const typename basic_client_buffer<Document, Selector>::net_type&
01226 basic_client_buffer<Document, Selector>::net6_client() const
01227 {
01228         return dynamic_cast<const net_type&>(
01229                 *basic_buffer<Document, Selector>::m_net.get()
01230         );
01231 }
01232 
01233 } // namespace obby
01234 
01235 #endif // _OBBY_CLIENT_BUFFER_HPP_

Generated on Fri Jan 11 10:01:32 2008 for obby by  doxygen 1.5.1