diff options
| author | Paul Buetow <paul@buetow.org> | 2013-04-06 13:14:41 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2013-04-06 13:14:41 +0200 |
| commit | 9cd3ccffd5372dfde3af478e3f832f18db4be3f1 (patch) | |
| tree | 631c295a4a4a16b57502b847626763a279bf6df7 /ychat-0.2 | |
| parent | 13aaf70af703748fe096e0664c305cd202637ad2 (diff) | |
tagging tags
Diffstat (limited to 'ychat-0.2')
65 files changed, 2768 insertions, 0 deletions
diff --git a/ychat-0.2/CHAT.cpp b/ychat-0.2/CHAT.cpp new file mode 100755 index 0000000..1358a06 --- /dev/null +++ b/ychat-0.2/CHAT.cpp @@ -0,0 +1,10 @@ +#ifndef GCHT_CXX +#define GCHT_CXX + +#include "CHAT.h" + +using namespace std; + +chat* CHAT::obj; + +#endif diff --git a/ychat-0.2/CHAT.h b/ychat-0.2/CHAT.h new file mode 100755 index 0000000..6c015f4 --- /dev/null +++ b/ychat-0.2/CHAT.h @@ -0,0 +1,26 @@ +#ifndef GCHT_H +#define GCHT_H + +#include "chat.h" + +using namespace std; + +class CHAT +{ +private: + static chat* obj; + +public: + static void init() + { + obj = new chat(); + } + + static chat& get() + { + return *obj; + } +}; + + +#endif diff --git a/ychat-0.2/CONF.cpp b/ychat-0.2/CONF.cpp new file mode 100755 index 0000000..8b5441c --- /dev/null +++ b/ychat-0.2/CONF.cpp @@ -0,0 +1,10 @@ +#ifndef GCON_CXX +#define GCON_CXX + +#include "CONF.h" + +using namespace std; + +conf* CONF::obj; + +#endif diff --git a/ychat-0.2/CONF.h b/ychat-0.2/CONF.h new file mode 100755 index 0000000..f3dc5c9 --- /dev/null +++ b/ychat-0.2/CONF.h @@ -0,0 +1,26 @@ +#ifndef GCON_H +#define GCON_H + +#include "conf.h" + +using namespace std; + +class CONF +{ +private: + static conf* obj; + +public: + static void init() + { + obj = new conf( CONFILE ); + } + + static conf& get() + { + return *obj; + } +}; + + +#endif diff --git a/ychat-0.2/HTML.cpp b/ychat-0.2/HTML.cpp new file mode 100755 index 0000000..a93bc0a --- /dev/null +++ b/ychat-0.2/HTML.cpp @@ -0,0 +1,10 @@ +#ifndef GHTM_CXX +#define GHTM_CXX + +#include "HTML.h" + +using namespace std; + +html* HTML::obj; + +#endif diff --git a/ychat-0.2/HTML.h b/ychat-0.2/HTML.h new file mode 100755 index 0000000..16bf13d --- /dev/null +++ b/ychat-0.2/HTML.h @@ -0,0 +1,26 @@ +#ifndef GHTM_H +#define GHTM_H + +#include "html.h" + +using namespace std; + +class HTML +{ +private: + static html* obj; + +public: + static void init() + { + obj = new html(); + } + + static html& get() + { + return *obj; + } +}; + + +#endif diff --git a/ychat-0.2/MUTX.cpp b/ychat-0.2/MUTX.cpp new file mode 100755 index 0000000..41382f3 --- /dev/null +++ b/ychat-0.2/MUTX.cpp @@ -0,0 +1,10 @@ +#ifndef GMUT_CXX +#define GMUT_CXX + +#include "MUTX.h" + +using namespace std; + +mutx* MUTX::obj; + +#endif diff --git a/ychat-0.2/MUTX.h b/ychat-0.2/MUTX.h new file mode 100755 index 0000000..f2e9980 --- /dev/null +++ b/ychat-0.2/MUTX.h @@ -0,0 +1,26 @@ +#ifndef GMUT_H +#define GMUT_H + +#include "mutx.h" + +using namespace std; + +class MUTX +{ +private: + static mutx* obj; + +public: + static void init() + { + obj = new mutx(); + } + + static mutx& get() + { + return *obj; + } +}; + + +#endif diff --git a/ychat-0.2/Makefile b/ychat-0.2/Makefile new file mode 100755 index 0000000..7506171 --- /dev/null +++ b/ychat-0.2/Makefile @@ -0,0 +1,12 @@ +SRCS=base.cpp chat.cpp CHAT.cpp cmnd.cpp conf.cpp CONF.cpp cont.cpp html.cpp HTML.cpp main.cpp mutx.cpp MUTX.cpp name.cpp pool.cpp reqp.cpp room.cpp sock.cpp SOCK.cpp thrd.cpp TOOL.cpp user.cpp +OBJS=$(SRCS:.cpp=.o) +CC=c++ +LDFLAGS=-lstdc++ -g +LDADD=-pthread -D_THREAD_SAFE +all: ychat +$(SRCS): + $(CC) $(CFLAGS) -c $*.cpp +ychat: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDADD) +clean: + rm *.o diff --git a/ychat-0.2/README.txt b/ychat-0.2/README.txt new file mode 100755 index 0000000..af513e8 --- /dev/null +++ b/ychat-0.2/README.txt @@ -0,0 +1,177 @@ +yChat++; Homepage: www.yChat.org; Version 0.2 +Copyright (C) 2003 Paul C. Buetow, Volker Richter +----------------------------------------------------------------- + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +----------------------------------------------------------------- + +Notes: I programmed this on FreeBSD but should also compile without +big problems on Linux or other UNIX-like systems. +If you have tested one of those then pleace write me the name of the OS, +kernel version, make version and compiler & version. I will list it +right here: + +The following platforms have been tested with success: + +- FreeBSD 5.0-RELEASE, GCC 3.2.1, FreeBSD 5.0 make and GNU make 3.80 + +- Linux Kernel 2.4.19, GCC 3.2.0, GNU make 3.79.1 + +Before you compile the source you have to be sure to use at least GCC +version 3.x with pthreads enabled. ( Type gcc -v to check it ). +GCC 2.95 did not work while testing on linux and won't be supported! + +If you like to support yChat++, please write me an email and tell me +what you can/like/would help ;-]. Please also take a look at the +yChat++ homepage ( www.yChat.org ). + +Installation: Just invoke "make", edit the conf.txt and run the +server with ./ychat, point your webbrowser to http://yourip:port/index.html +( ignoring the index.html on the end of the url will not work! ). +... have fun :-). + +If you like customizing the design/layout/language of yChat, you will have +to edit msgs.h and glob.h before you compile the sources. Afterwards you can +change the html-template files which are placed in the html/ subdirectory. + +Files: + +conf.txt - The yChat configuration file. ( read by conf.cpp ). + +base.cpp - Encapsulates vector fields of room's or user ( may be later + hash_maps ) and provides methods for manipulating base data + objects. + +main.cpp - This includes the required manager headers for starting + the server and finally regulates the correct starting. + +pool.cpp - The implementation of the thread pool. all threads are stored + in a queue. Each thread will be reused if the assigned job is + finished. + +reqp.cpp - This class implements the http request parser. If a client + starts a request to the server the reqp class will be + invoked. + +room.cpp - Specifies a chat room. For each chat room an instance of + this class exists. + +thrd.cpp - This class is needed by sock.cpp while creating a POSIX thread. + All data which a thread needs to do its tasks are stored in a + thrd object and then a pointer to it will be passed to the + POSIX thread function. + +user.cpp - Specifies a chat user. For each chat user an instance of + this class exists. + +Abstract classes: + +cont.cpp - All classes which need to store "key - value" data sets + inherit from this class. ( cont for content ). + +name.cpp - All classes which own a private member string name inherit + from this class. It also provides public get_name and + set_name methods. + +As described ( main.cpp ), there are so called managers. Managers are +accessible through their assigned wrapper classes and may be +instanciated only once. + +chat.cpp - The chat manager. Is responsible for managing the internal + data structure of the system and also covers a lot of + important methods of the system. + +conf.cpp - The config manager. Parses the config file specified in + glob.h and stores all the values of it in a map. + +html.cpp - The html-template manager. Reads the requested html-template + files, stores them in an internal cache ( averts reading + template-files from hd twice or more ) and parses the + partivular template in order to substituate dynamic values + of it. + +mutx.cpp - The mutex manager. Contains all global mutex handlers for + synchronizing POSIX thread shared data. until now only the + stdout is synchronized by mutx.cpp because most of objects + use their own mutex'. + +sock.cpp - The socket manager. Manages the socket connections. There + are multiplexed sockets. For each requests a new POSIX thread + will be created. + +Files written in capital letters contain static C++ classes + +CHAT.cpp - Static wrapper for the dynamic chat class. holds one global + reachable instance of chat until the program shuts down. + +CONF.cpp - Static wrapper for the dynamic conf class. holds one global + reachable instance of conf until the program shuts down. + +HTML.cpp - Static wrapper for the dynamic html class. holds one global + reachable instance of conf until the program shuts down. + +MUTX.cpp - Static wrapper for the dynamic mutx class. holds one global + reachable instance of conf until the program shuts down. + +SOCK.cpp - Static wrapper for the dynamic sock class. holds one global + reachable instance of conf until the program shuts down. + +TOOL.cpp - Static class which includes some usefull global reachable + methods which are not integraded in independent classes. + +Special header files ( all other header files which are not listed here +belong to their respective .cpp files ): + +data.h - Implements a generic class ( template class ) for accessing + data from a base ( see base.cpp ) object. this methods are + all inline and use rekursive algorithm and function pointers. + +glob.h - Defines global variables which are known by compilation + time. + +incl.h - This file is included from every other header file and + includes a set of headers which every class should be able + to use. + +msgs.h - Defines console output messages for verbosity level 0 ( see + glob.h for setting up verbosity levels ). and also defines + all the system messages. you may edit this file for translating + the system user language. + + +The basic class structure: + + base + | + | + data<type> name + / \ / \ + / \ / \ +chat room user + + cont + / \ + / \ +conf html + +Version Lines of code + 0.1 2402 + 0.2 2377 + +New in 0.2: + - POST request now work. + - Thread pool ( pool.cpp ). + - Bugfixes diff --git a/ychat-0.2/SOCK.cpp b/ychat-0.2/SOCK.cpp new file mode 100755 index 0000000..c5b451e --- /dev/null +++ b/ychat-0.2/SOCK.cpp @@ -0,0 +1,10 @@ +#ifndef GSOC_CXX +#define GSOC_CXX + +#include "SOCK.h" + +using namespace std; + +sock* SOCK::obj; + +#endif diff --git a/ychat-0.2/SOCK.h b/ychat-0.2/SOCK.h new file mode 100755 index 0000000..dacc05f --- /dev/null +++ b/ychat-0.2/SOCK.h @@ -0,0 +1,26 @@ +#ifndef GSOC_H +#define GSOC_H + +#include "sock.h" + +using namespace std; + +class SOCK +{ +private: + static sock* obj; + +public: + static void init() + { + obj = new sock(); + } + + static sock& get() + { + return *obj; + } +}; + + +#endif diff --git a/ychat-0.2/TOOL.cpp b/ychat-0.2/TOOL.cpp new file mode 100755 index 0000000..7709695 --- /dev/null +++ b/ychat-0.2/TOOL.cpp @@ -0,0 +1,33 @@ +#ifndef TOOL_CXX +#define TOOL_CXX + +#include <time.h> +#include "TOOL.h" + +int +TOOL::string2int( string s_digit ) +{ + auto const char *digit = s_digit.c_str(); + int result = 0; + + // Convert each digit char and add into result. + while (*digit >= '0' && *digit <='9') { + result = (result * 10) + (*digit - '0'); + digit++; + } + + // Check that there were no non-digits at end. + if (*digit != 0) { + return -1; + } + + return result; +} + +long +TOOL::unixtime() +{ + return (long) time( NULL ); +} + +#endif diff --git a/ychat-0.2/TOOL.h b/ychat-0.2/TOOL.h new file mode 100755 index 0000000..de2c4a2 --- /dev/null +++ b/ychat-0.2/TOOL.h @@ -0,0 +1,15 @@ +#ifndef TOOL_H +#define TOOL_H + +#include "incl.h" + +using namespace std; + +class TOOL +{ +public: + static int string2int( string s_digit ); + static long unixtime(); +}; + +#endif diff --git a/ychat-0.2/base.cpp b/ychat-0.2/base.cpp new file mode 100755 index 0000000..9a67340 --- /dev/null +++ b/ychat-0.2/base.cpp @@ -0,0 +1,88 @@ +// template class data implementation; + +#ifndef BASE_CPP +#define BASE_CPP + +#include "base.h" + +base::base() +{ + pthread_mutex_init (&mut_vec_elem, NULL ); +} + +base::~base( ) +{ + pthread_mutex_destroy( &mut_vec_elem ); +} + +void +base::add_elem( name* p_name ) +{ + pthread_mutex_lock ( &mut_vec_elem ); + vec_elem.push_back ( p_name ); + pthread_mutex_unlock( &mut_vec_elem ); +} + +bool +base::del_elem( string &s_name ) +{ + vector<name*>::iterator iter; + pthread_mutex_lock ( &mut_vec_elem ); + + iter = vec_elem.begin(); + while( iter != vec_elem.end() ) + { + if ( (*iter)->get_name() == s_name ) + { + vec_elem.erase( iter ); + pthread_mutex_unlock( &mut_vec_elem ); + return true; + } + iter++; + } + + pthread_mutex_unlock( &mut_vec_elem ); + return false; +} + +name* +base::get_elem( string &s_name, bool &b_found ) +{ + vector<name*>::iterator iter; + pthread_mutex_lock ( &mut_vec_elem ); + + iter = vec_elem.begin(); + while( iter != vec_elem.end() ) + { + if ( (*iter)->get_name() == s_name ) + { + b_found = true; + pthread_mutex_unlock( &mut_vec_elem ); + return (*iter); + } + iter++; + } + + pthread_mutex_unlock( &mut_vec_elem ); + + b_found = false; + + return new name(); +} + +void +base::run_func( void (*func)(name*, void*), void* v_arg ) +{ + vector<name*>::iterator iter; + pthread_mutex_lock ( &mut_vec_elem ); + + // execute func foreach element of vec_elem with + // 1st argument: a pointer of a element of vec_elem. + // 2nd argument: a void pointer of a object. + for( iter = vec_elem.begin(); iter != vec_elem.end(); iter++ ) + ( *func ) ( (*iter), v_arg ); + + pthread_mutex_unlock( &mut_vec_elem ); +} + +#endif diff --git a/ychat-0.2/base.h b/ychat-0.2/base.h new file mode 100755 index 0000000..d1c37ba --- /dev/null +++ b/ychat-0.2/base.h @@ -0,0 +1,28 @@ +// template class data declaration; + +#ifndef BASE_H +#define BASE_H + +#include <vector> +#include "incl.h" +#include "name.h" + +class base +{ +private: + vector<name*> vec_elem ; + pthread_mutex_t mut_vec_elem; + +public: + base(); + ~base(); + + virtual void add_elem( name* p_name ); // add a element. + virtual bool del_elem( string &s_name ); // delete a alement. + virtual name* get_elem( string &s_name, bool &b_found ); // get a element. + + // execute func on all elements of vec_elem. v_pointer is the argument. + virtual void run_func( void (*func)(name*, void*), void* v_arg ); +}; + +#endif diff --git a/ychat-0.2/chat.cpp b/ychat-0.2/chat.cpp new file mode 100755 index 0000000..7b0ccd2 --- /dev/null +++ b/ychat-0.2/chat.cpp @@ -0,0 +1,121 @@ +// class chat implementation. + +#ifndef CHAT_CXX +#define CHAT_CXX + +#include "chat.h" +#include "CONF.h" +#include "MUTX.h" + +using namespace std; + +chat::chat( ) +{ +} + +chat::~chat( ) +{ +} + +user* +chat::get_user( string &s_user ) +{ + bool b_flag; + return get_user( s_user, b_flag ); +} + +user* +chat::get_user( string &s_user, bool &b_found ) +{ + container param; + + param.elem[0] = (void*) &s_user ; + param.elem[1] = (void*) &b_found; + + b_found = false; + + run_func( get_user_, (void*)¶m ); + + if ( *( (bool*)param.elem[1] ) ) + return (user*)param.elem[2]; +} + +void +chat::get_user_( name *name_obj, void *v_arg ) +{ + container* param = (container*) v_arg; + room *room_obj = static_cast<room*>(name_obj); + param->elem[2] = (void*)room_obj->get_elem( *((string*)param->elem[0]), *((bool*)param->elem[1]) ); +} + +void +chat::login( map_string &map_params ) +{ + string s_user = map_params["nick"]; + + // prove if nick is empty + if ( s_user.empty() ) + { + map_params["INFO"] = E_NONICK; + map_params["request"] = CONF::get().get_val( "STARTMPL" ); // redirect to the startpage. + return; + } + + bool b_flag; + + // prove if nick is already online / logged in. + get_user( s_user, b_flag ); + if ( b_flag ) + { + map_params["INFO"] = E_ONLINE; + map_params["request"] = CONF::get().get_val( "STARTMPL" ); + return; + } + + string s_room = map_params["room"]; + room* p_room = get_room( s_room , b_flag ); + + // if room does not exist add room to list! + if ( ! b_flag ) + { + p_room = new room( s_room ); + +#ifdef _VERBOSE + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cout << NEWROOM << s_room << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); +#endif + + add_elem( p_room ); + } + + user *p_user = new user( s_user ); + + // add user to the room. + p_room->add_user( p_user ); + + // post "username enters the chat" into the room. + p_room->msg_post( new string( s_user.append( USERENTR ) ) ); + +#ifdef _VERBOSE + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cout << LOGINPR << s_user << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); +#endif +} + +void +chat::post( user* u_user, map_string &map_params ) +{ + string s_msg( "<font color=\"" ); + s_msg.append( u_user->get_col1() ) + .append( "\">" ) + .append( u_user->get_name() ) + .append( ": " ) + .append( map_params["message"] ) + .append( "</font><br>\n" ); + + u_user->get_p_room()->msg_post( &s_msg ); +} + +#endif diff --git a/ychat-0.2/chat.h b/ychat-0.2/chat.h new file mode 100755 index 0000000..164c0c4 --- /dev/null +++ b/ychat-0.2/chat.h @@ -0,0 +1,40 @@ +// class chat declaration. + +#ifndef CHAT_H +#define CHAT_H + +#include <vector> +#include "incl.h" +#include "data.h" +#include "room.h" +#include "user.h" + +using namespace std; + +class chat : public data<room> +{ +private: + +public: + room* get_room( string &s_name, bool &b_found ) + { + return static_cast<room*>( get_elem( s_name, b_found ) ); + } + + // public methods: + explicit chat(); // a standard constructor. + ~chat(); // destructor. + + // get the object of a specific user. + virtual user* get_user( string &s_nick ); + virtual user* get_user( string &s_nick, bool &b_found ); + static void get_user_( name* name_obj, void *v_arg ); + + // will be called every time a user tries to login. + virtual void login( map_string &map_params ); + + // will be called if a user posts a message. + virtual void post ( user* u_user, map_string &map_params ); +}; + +#endif diff --git a/ychat-0.2/cmnd.cpp b/ychat-0.2/cmnd.cpp new file mode 100755 index 0000000..9ab008a --- /dev/null +++ b/ychat-0.2/cmnd.cpp @@ -0,0 +1,19 @@ +// class cmnd implementation. + +#ifndef CMND_CXX +#define CMND_CXX + +#include "cmnd.h" +#include "MUTX.h" + +using namespace std; + +cmnd::cmnd( ) +{ +} + +cmnd::~cmnd() +{ +} + +#endif diff --git a/ychat-0.2/cmnd.h b/ychat-0.2/cmnd.h new file mode 100755 index 0000000..2eb1db2 --- /dev/null +++ b/ychat-0.2/cmnd.h @@ -0,0 +1,18 @@ +// class cmnd declaration. + +#ifndef CMND_H +#define CMND_H + +#include "incl.h" + +using namespace std; + +class cmnd +{ +public: + // public methods: + explicit cmnd( ); // a standard constructor. + ~cmnd( ); +}; + +#endif diff --git a/ychat-0.2/conf.cpp b/ychat-0.2/conf.cpp new file mode 100755 index 0000000..5214edb --- /dev/null +++ b/ychat-0.2/conf.cpp @@ -0,0 +1,75 @@ +// class conf implementation. + +#ifndef CONF_CXX +#define CONF_CXX + +#include <fstream> +#include "conf.h" + +using namespace std; + +conf::conf( string s_conf = CONFILE ) : name( s_conf ) +{ + parse( ); // parse the config file. +} + +conf::~conf() +{ +} + +void +conf::parse() +{ +#ifdef _VERBOSE + cout << CFILEOK << get_name() << endl; +#endif + + ifstream fs_conf( get_name().c_str() ); + + if ( ! fs_conf ) + { +#ifdef _VERBOSE + cout << CFILENO << get_name() << endl; +#endif + return; + } + + char c_buf[READBUF]; + + while( fs_conf.getline( c_buf, READBUF ) ) + { + string s_token( c_buf ); + unsigned int ui_pos = s_token.find( "#", 0 ); + + // if line is commented out: + if ( ui_pos == 0 ) + continue; + + ui_pos = s_token.find( ";", 0 ); + + // if token has not been found. + if ( ui_pos == string::npos ) + continue; + + s_token = s_token.substr( 0 , --ui_pos ); + ui_pos = s_token.find ( "\"", 0 ); + + if ( ui_pos == string::npos ) + continue; + + string s_val = s_token.substr( ui_pos+1, s_token.length() ); + string s_key = s_token.substr( 0 , --ui_pos ); + +#ifdef VERBOSE + cout << s_key << "=" << s_val << endl; +#endif + + // fill the map. + map_vals[s_key] = s_val; + } + + fs_conf.close(); + fs_conf.~ifstream(); +} + +#endif diff --git a/ychat-0.2/conf.h b/ychat-0.2/conf.h new file mode 100755 index 0000000..a3b5022 --- /dev/null +++ b/ychat-0.2/conf.h @@ -0,0 +1,24 @@ +// class conf declaration. this class parses the server config file. + +#ifndef CONF_H +#define CONF_H + +#include "incl.h" +#include "cont.h" +#include "name.h" + +using namespace std; + +class conf : public cont, name +{ +private: + +public: + // public methods: + conf ( string s_conf ); // standard constructor. + ~conf(); // standard destructor. + + virtual void parse( ); // parses the config file. +}; + +#endif diff --git a/ychat-0.2/conf.txt b/ychat-0.2/conf.txt new file mode 100755 index 0000000..c31c554 --- /dev/null +++ b/ychat-0.2/conf.txt @@ -0,0 +1,47 @@ +# +# please notice this: +# the server parses this configuration file while starting or by an +# administrator's request. +# +# not allowed are semicolons ';' inside or before the quotes " ", +# otherwise this might result in errors. +# +# the syntax is easy: KEYNAME="value"; +# +# all lines which do not contain a semicolon and at least two quotes +# or start with a # will be ignored. +# +# greets, paul c. buetow ( snooper@ychat.org ); +# + +# server specific configurations ( not allowed to be removed ): + +HTMLTEMP="html/"; # directory of the html-template files. +THRDPOOL="10"; # thread pool size. every time all threads are used so many new + # threads will be added to the pool. +THRDQUEU="100"; # length of the thread pool queue. +SRVRPORT="2000"; # local port on which the server listens. +STRDROOM="Lounge"; # the name of the standard room. + +# the html template file which will be send if the requested file does not exists. +NOTFOUND="notfound.html"; +# specifies the standard start html-template. +STARTMPL="index.html"; +# user's standard nick color. +USERCOL1="#000000"; + +# superuser level names. level 0 has the most provileges. +SULEVEL0="Coder"; # programmer. +SULEVEL1="Admin"; # administrator. +SULEVEL2="Magic"; # super user with special privileges. +SULEVEL3="Super"; # temporary super user. +SULEVEL4="Basic"; # normal user without special privileges. +SULEVEL5="Guest"; # guest user, has almost no privileges. +SULEVEL6="Restr"; # a very restricted user. +SULEVEL7="Outbn"; # banned out of the system. + +# values which are used by the html-templates and are not sticked within the yC++ core source! +GRAPHICS="http://paul.buetow.info/yChat"; # url for graphic files etc. +PGETITLE="yChat++ Basic - Fast Simple Extensible"; + +# end. diff --git a/ychat-0.2/cont.cpp b/ychat-0.2/cont.cpp new file mode 100755 index 0000000..91cbbca --- /dev/null +++ b/ychat-0.2/cont.cpp @@ -0,0 +1,24 @@ +// class cont implementation. + +#ifndef CONT_CXX +#define CONT_CXX + +#include "cont.h" +#include "MUTX.h" + +using namespace std; + +string +cont::get_val( string s_key ) +{ + if ( map_vals.find( s_key ) != map_vals.end() ) + return map_vals[ s_key ]; + return string(); +} + +cont::~cont() +{ + map_vals.~map_string(); +} + +#endif diff --git a/ychat-0.2/cont.h b/ychat-0.2/cont.h new file mode 100755 index 0000000..06a09e2 --- /dev/null +++ b/ychat-0.2/cont.h @@ -0,0 +1,25 @@ +// class cont declaration. defines a simple data container class. + +#ifndef CONT_H +#define CONT_H + +#include "incl.h" + +using namespace std; + +class cont +{ +protected: + map_string map_vals; + +public: + cont::~cont(); + + // small inline methods: + void clear_vals() { map_vals.clear(); } // removes all values. + + // public methods: + virtual string get_val( string s_key ); // get a specific map_vals value. +}; + +#endif diff --git a/ychat-0.2/data.h b/ychat-0.2/data.h new file mode 100755 index 0000000..55dbc69 --- /dev/null +++ b/ychat-0.2/data.h @@ -0,0 +1,62 @@ +#ifndef DATA_H +#define DATA_H + +#include "base.h" +#include "MUTX.h" + +using namespace std; + +template<class type> +class data : public base +{ +public: + + // chat::msg_post sends to all users of the system a message. + // room::msg_post sends to all users of the room a message. + // user::msg_post sends to the user a message. + void msg_post( string *s_msg ) + { + run_func( &data<type>::msg_post_ , (void*)s_msg ); + } + static void msg_post_( name* name_obj, void* v_arg ) + { + string *p_msg = (string*) v_arg; + type *type_obj = static_cast<type*>(name_obj); + + type_obj -> msg_post( p_msg ); + } + + void get_data( map_string *p_map_string ) + { + run_func( &data<type>::get_data_ , (void*)p_map_string ); + } + static void get_data_( name* name_obj, void* v_arg ) + { + map_string *map_params = (map_string*) v_arg; + type *type_obj = static_cast<type*>(name_obj); + + type_obj -> get_data ( map_params ); + } + + // chat::get_user_list gets a list of all users of the system. + // room::get_user_list gets a list of all users of the room. + // user::get_user_list gets a "list" of a user <font color="usercolor">username</font>seperator + void get_user_list( string &s_list, string &s_seperator ) + { + + container c; + c.elem[0] = (void*) &s_list; + c.elem[1] = (void*) &s_seperator; + + run_func( &data<type>::get_user_list_, (void*)&c ); + } + static void get_user_list_( name* name_obj, void* v_arg ) + { + container *c = (container*) v_arg; + type *type_obj = static_cast<type*>(name_obj); + + type_obj -> get_user_list( *((string*)c->elem[0]), *((string*)c->elem[1]) ); + } +}; + +#endif diff --git a/ychat-0.2/gfx/CVS/Entries b/ychat-0.2/gfx/CVS/Entries new file mode 100644 index 0000000..5178e8f --- /dev/null +++ b/ychat-0.2/gfx/CVS/Entries @@ -0,0 +1,3 @@ +/y_ani_black.gif/1.1.1.1/Fri Mar 21 15:54:56 2003// +/y_ani_white.gif/1.1.1.1/Fri Mar 21 15:54:56 2003// +D diff --git a/ychat-0.2/gfx/CVS/Repository b/ychat-0.2/gfx/CVS/Repository new file mode 100644 index 0000000..6d97963 --- /dev/null +++ b/ychat-0.2/gfx/CVS/Repository @@ -0,0 +1 @@ +ychat/gfx diff --git a/ychat-0.2/gfx/CVS/Root b/ychat-0.2/gfx/CVS/Root new file mode 100644 index 0000000..6de547b --- /dev/null +++ b/ychat-0.2/gfx/CVS/Root @@ -0,0 +1 @@ +:pserver:paul@internal.ath.cx:/home/cvsroot diff --git a/ychat-0.2/gfx/y_ani_black.gif b/ychat-0.2/gfx/y_ani_black.gif Binary files differnew file mode 100755 index 0000000..06274c2 --- /dev/null +++ b/ychat-0.2/gfx/y_ani_black.gif diff --git a/ychat-0.2/gfx/y_ani_white.gif b/ychat-0.2/gfx/y_ani_white.gif Binary files differnew file mode 100755 index 0000000..168c937 --- /dev/null +++ b/ychat-0.2/gfx/y_ani_white.gif diff --git a/ychat-0.2/glob.h b/ychat-0.2/glob.h new file mode 100755 index 0000000..37741f8 --- /dev/null +++ b/ychat-0.2/glob.h @@ -0,0 +1,56 @@ +// global variables. + +#ifndef GLOB_H +#define GLOB_H + +#include <map> +#include <pthread.h> + +// definition of boolean values. +#define true 1 +#define false 0 + +// config filename. +#define CONFILE "conf.txt" + +// the highest port which is allowed to use. if ychat is unable to create the server +// socket it will increment the port number and tries to create another socket. +// this procedure will go on until MAXPORT is reached. +#define MAXPORT 65535 + +// max length of a line read from a socket or a file ( config-file, html-template ). +#define READBUF 1024 + +// definition for verbosity level 0 ( normal outputs ). see vmsg.h for custumizing all +// the messages. this messages will only printed out by the master thread. +#define _VERBOSE + + +////////////////////////////////////////////////////////////////////////////////////////// +// DO NOT CHANGE ANYTHING BEHIND THIS LINE! +////////////////////////////////////////////////////////////////////////////////////////// + +using namespace std; + +// internal rang descriptors ( their external names may be specified different ) +enum rang +{ + CODER , // programmer. + ADMIN , // administrator. + MAGIC , // super user with special privileges. + SUPER , // temporary super user. + BASIC , // normal user without special privileges. + GUEST , // guest user, has almost no privileges. + RESTR , // a very restrivted user. + OUTBN // banned out of the system. +}; + +// some custom typedefs for datatypes which are needed often. +typedef map<string, string> map_string; + +struct container +{ + void* elem[3]; +}; + +#endif diff --git a/ychat-0.2/html.cpp b/ychat-0.2/html.cpp new file mode 100755 index 0000000..ad0de08 --- /dev/null +++ b/ychat-0.2/html.cpp @@ -0,0 +1,132 @@ +// class html implementation. + +#ifndef HTML_CXX +#define HTML_CXX + +#include <fstream> +#include "html.h" +#include "CHAT.h" +#include "MUTX.h" + +using namespace std; + +html::html( ) +{ + set_name( CONF::get().get_val( "HTMLTEMP" ) ); + pthread_mutex_init( &mut_map_vals, NULL ); +} + +html::~html( ) +{ + pthread_mutex_destroy( &mut_map_vals ); +} + +void +html::clear_cache( ) +{ + pthread_mutex_lock ( &mut_map_vals ); + clear_vals(); + pthread_mutex_unlock( &mut_map_vals ); +} + +string +html::parse( map_string &map_params ) +{ + string s_file = map_params["request"]; + + // check if s_file is in the container. + pthread_mutex_lock ( &mut_map_vals ); + string s_templ = get_val( s_file ); + pthread_mutex_unlock( &mut_map_vals ); + + // if not, read file. + if ( s_templ.empty() ) + { + auto string s_path = get_name(); + auto ifstream fs_templ( s_path.append( s_file ).c_str() ); + + if ( ! fs_templ ) + { + map_params["request"] = CONF::get().get_val( "NOTFOUND" ); + return parse( map_params ); + } + + auto char c_buf[READBUF]; + + while( fs_templ.getline( c_buf, READBUF ) ) + s_templ.append( string( c_buf ).append( "\n" ) ); + + fs_templ.close(); + +#ifdef _VERBOSE + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cout << TECACHE << s_path << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); +#endif + + // cache file. + pthread_mutex_lock ( &mut_map_vals ); + map_vals[ s_file ] = s_templ; + pthread_mutex_unlock( &mut_map_vals ); + } + + // find %%KEY%% token and substituate those. + auto unsigned int pos[2]; + pos[0] = pos[1] = 0; + + do + { + pos[0] = s_templ.find( "%%", pos[1] ); + + if ( pos[0] == string::npos ) + break; + + pos[0] += 2; + pos[1] = s_templ.find( "%%", pos[0] ); + + if ( pos[0] == string::npos ) + break; + + // get key and val. + auto string s_key = s_templ.substr( pos[0], pos[1]-pos[0] ); + auto string s_val = CONF::get().get_val( s_key ); + + // if s_val is empty use map_params. + if ( s_val.empty() ) + s_val = map_params[ s_key ]; + + // substituate key with val. + s_templ.replace( pos[0]-2, pos[1]-pos[0]+4, s_val ); + + // calculate the string displacement. + auto int i_dif = s_val.length() - ( pos[1] - pos[0] + 4); + + pos[1] += 2 + i_dif; + + } + while( true ); + + return s_templ; +} + +void +html::online_list( user *p_user, map_string &map_params ) +{ + // prepare user_list. + string s_list ( "" ); + string s_seperator( "<br>" ); + + p_user->get_p_room()->get_user_list( s_list, s_seperator ); + + // use the collected data as a message in html-templates. + map_params["MESSAGE"] = s_list; + + // renew the timestamp. + p_user->renew_stamp(); + + // send a ping to the client chat stream. + p_user->msg_post( new string("\n") ); +} + +#endif + diff --git a/ychat-0.2/html.h b/ychat-0.2/html.h new file mode 100755 index 0000000..9acf5a9 --- /dev/null +++ b/ychat-0.2/html.h @@ -0,0 +1,42 @@ +// class html declaration. this class manages the html-template files. + +#ifndef HTML_H +#define HTML_H + +#include "incl.h" +#include "cont.h" +#include "CONF.h" +#include "user.h" +#include "name.h" + + +using namespace std; + +class html : public cont, name +{ +private: +// needed for synchronizing the map_vals. + pthread_mutex_t mut_map_vals; + +public: + // public methods. + explicit html( ); // simple constructor. + ~html( ); + + // clears the template cache so that new html templates will be read + // from hard disk. this method is needed after changeing s.t. on + // the html-template files. + void clear_cache( ); + + // returns a parsed html-template. this method will check first if the + // required html-template exists inside the classes template cache. if not + // then the file will be read from file and added to the cache. + // afterwards the html-template will be parsed and returned. + // map_params contains the client request parameters which also will be + // used for string substituation. + virtual string parse( map_string &map_params ); + + virtual void online_list( user *p_user, map_string &map_params ); +}; + +#endif diff --git a/ychat-0.2/html/CVS/Entries b/ychat-0.2/html/CVS/Entries new file mode 100644 index 0000000..6738646 --- /dev/null +++ b/ychat-0.2/html/CVS/Entries @@ -0,0 +1,9 @@ +/blank.html/1.1.1.1/Fri Mar 21 15:54:56 2003// +/frameset.html/1.1.1.1/Fri Mar 21 15:54:56 2003// +/index.html/1.2/Sun Mar 23 19:03:13 2003// +/input.html/1.1.1.1/Fri Mar 21 15:54:56 2003// +/notfound.html/1.1.1.1/Fri Mar 21 15:54:56 2003// +/online.html/1.1.1.1/Fri Mar 21 15:54:56 2003// +/stream.html/1.1.1.1/Fri Mar 21 15:54:56 2003// +/y_ani.gif/1.1.1.1/Fri Mar 21 15:54:56 2003// +D diff --git a/ychat-0.2/html/CVS/Repository b/ychat-0.2/html/CVS/Repository new file mode 100644 index 0000000..3648237 --- /dev/null +++ b/ychat-0.2/html/CVS/Repository @@ -0,0 +1 @@ +ychat/html diff --git a/ychat-0.2/html/CVS/Root b/ychat-0.2/html/CVS/Root new file mode 100644 index 0000000..6de547b --- /dev/null +++ b/ychat-0.2/html/CVS/Root @@ -0,0 +1 @@ +:pserver:paul@internal.ath.cx:/home/cvsroot diff --git a/ychat-0.2/html/blank.html b/ychat-0.2/html/blank.html new file mode 100755 index 0000000..4ddd1a7 --- /dev/null +++ b/ychat-0.2/html/blank.html @@ -0,0 +1,4 @@ +<html> + <body> + </body> +</html> diff --git a/ychat-0.2/html/frameset.html b/ychat-0.2/html/frameset.html new file mode 100755 index 0000000..fe6b973 --- /dev/null +++ b/ychat-0.2/html/frameset.html @@ -0,0 +1,20 @@ +<html> +<head> +<title> + %%PGETITLE%% +</title> +</head> + <frameset rows="*,60"> + <noframes> + Your browser does not support frames, + </noframes> + <frameset cols="*,150"> + <frame src="stream.html?event=stream&nick=%%nick%%&tmpid=%%tmpid%%" name="stream"> + <frame src="online.html?event=online&nick=%%nick%%&tmpid=%%tmpid%%" name="online"> + </frameset> + <frameset rows="*,0"> + <frame src="input.html?event=input&nick=%%nick%%&tmpid=%%tmpid%%" name="input"> + <frame src="blank.html" name="blank"> + </frameset> + </frameset> +</html> diff --git a/ychat-0.2/html/index.html b/ychat-0.2/html/index.html new file mode 100755 index 0000000..172c851 --- /dev/null +++ b/ychat-0.2/html/index.html @@ -0,0 +1,31 @@ +<html> +<head> +<title> + %%PGETITLE%% +</title> +</head> +<body> +Welcome to +<pre> + ___ _ _ + _ _ / __\ |__ __ _| |_ +| | | |/ / | '_ \ / _` | __| +| |_| / /___| | | | (_| | |_ + \__, \____/|_| |_|\__,_|\__| + |___/ +</pre> + +<br> +%%PGETITLE%% +<br> +<br> +%%INFO%% +Enter your nick: +<form action="frameset.html" method="POST"> + <input type="hidden" name="event" value="login"> + <input type="hidden" name="room" value="%%STRDROOM%%"> + <input type="text" name="nick"> + <input type="submit" value="login"> +</form> +</body> +</html> diff --git a/ychat-0.2/html/input.html b/ychat-0.2/html/input.html new file mode 100755 index 0000000..e6fb016 --- /dev/null +++ b/ychat-0.2/html/input.html @@ -0,0 +1,32 @@ +<html> + <head> + <title> + %%PGETITLE%% + </title> + <script language="JavaScript"> + <!-- + function delout() + { + document.input.message.focus(); + document.input.message.select(); + document.input.submit(); + return false; + } + function selectinput() + { + document.input.message.select(); + } + //--> + </script> + </head> + <body> + <form name="input" action="input.html" target="blank" onsubmit="return delout();"> + <input type="hidden" name="event" value="post"> + <input type="hidden" name="nick" value="%%nick%%"> + <input type="hidden" name="tmpid" value="%%tmpid%%"> + <input type="text" name="message" size="50"> + <input type="submit" value="send"> + <input type="button" value="select" onclick="javascript:selectinput();"> + </form> + </body> +</html> diff --git a/ychat-0.2/html/notfound.html b/ychat-0.2/html/notfound.html new file mode 100755 index 0000000..574e341 --- /dev/null +++ b/ychat-0.2/html/notfound.html @@ -0,0 +1,10 @@ +<html> +<head> +<title> + %%PGETITLE%% +</title> +</head> +<body> + Page not found. +</body> +</html> diff --git a/ychat-0.2/html/online.html b/ychat-0.2/html/online.html new file mode 100755 index 0000000..7f29b0e --- /dev/null +++ b/ychat-0.2/html/online.html @@ -0,0 +1,6 @@ +<html> + <meta http-equiv="refresh" content="20"> + <body> + %%MESSAGE%% + </body> +</html> diff --git a/ychat-0.2/html/stream.html b/ychat-0.2/html/stream.html new file mode 100755 index 0000000..66f8bbd --- /dev/null +++ b/ychat-0.2/html/stream.html @@ -0,0 +1,29 @@ +<html> + <head> + <title> + %%PGETITLE%% + </title> + <script language="JavaScript"> + function autoScroll() + { + window.scroll(1, 50000 ); + timer = setTimeout('autoScroll()',200); + } + + autoScroll(); + + function stopScroll() + { + clearTimeout(timer); + } + + function startScroll() + { + timer = setTimeout('autoScroll()', 200); + } + </script> +</head> +<body> + Welcome to yChat %%nick%%! + <br> + <br> diff --git a/ychat-0.2/html/y_ani.gif b/ychat-0.2/html/y_ani.gif Binary files differnew file mode 100755 index 0000000..e730988 --- /dev/null +++ b/ychat-0.2/html/y_ani.gif diff --git a/ychat-0.2/incl.h b/ychat-0.2/incl.h new file mode 100755 index 0000000..f8e483f --- /dev/null +++ b/ychat-0.2/incl.h @@ -0,0 +1,16 @@ +// contains header files which are included by all classes. + +// include some std headers. +#include <iostream> + +// since thread synchronization is a big issue this header needs +// to be included by every other file too. +#include <pthread.h> + +// std::string. +#include <string> + +// include all the custom global variables. +#include "glob.h" +// include all the custom messages. +#include "msgs.h" diff --git a/ychat-0.2/main.cpp b/ychat-0.2/main.cpp new file mode 100755 index 0000000..2cbc713 --- /dev/null +++ b/ychat-0.2/main.cpp @@ -0,0 +1,86 @@ +/* + * yChat++; Homepage: www.yChat.org + * Copyright (C) 2003 Paul C. Buetow ( Snooper@yChat.org, ICQ: 11655527 ) + * ----------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +// needed for ignoring SIGPIPE. +#include <signal.h> + +// include header files which are included from every class too. +#include "incl.h" + +// include the chat manager. +#include "CHAT.h" + +// include the config manager. +#include "CONF.h" + +// include the html-template manager. +#include "HTML.h" + +// include the mutex manager for global synchronization. +#include "MUTX.h" + +// include the socket manager. +#include "SOCK.h" + +using namespace std; + +int main() +{ +#ifdef _VERBOSE + +cout << " ___ _ _ " << endl + << " _ _ / __\\ |__ __ _| |_ " << endl + << "| | | |/ / | '_ \\ / _` | __|" << endl + << "| |_| / /___| | | | (_| | |_ " << endl + << " \\__, \\____/|_| |_|\\__,_|\\__|" << endl + << " |___/ " << endl << endl + + << DESCRIP << endl + << VERSION << ", " + << CONTACT << endl + << SEPERAT << endl + << STARTMS << endl ; +#endif + + // ignore SIGPIPE. otherwise the server will shut down with "Broken pipe" if + // a client unexpected disconnects himself from a SOCK_STREAM. + signal( SIGPIPE, SIG_IGN ); + + // all the static data classes have to be initialized once. otherwise they will + // contain only empty pointers and the chat server won't work correctly. + // the order of the initializations is very importand. for example the HTML::init() + // invokations assumes an initialized CONF class. + MUTX::init(); // init the mutex manager. + CONF::init(); // init the config manager. + HTML::init(); // init the html-template manager. + SOCK::init(); // init the socket manager. + CHAT::init(); // init the chat manager. + + // start the socket manager. this one will listen for incoming http requests and will + // forward them to the specified routines which will generate a http response. + SOCK::get().start(); + +#ifdef _VERBOSE + cout << DOWNMSG << endl; +#endif + + return 0; +} diff --git a/ychat-0.2/msgs.h b/ychat-0.2/msgs.h new file mode 100755 index 0000000..f57301c --- /dev/null +++ b/ychat-0.2/msgs.h @@ -0,0 +1,38 @@ +#ifndef MSGS_H +#define MSGS_H + +// message templates. +// will post "nickname enters the chat" into the room. +#define USERENTR " enters the chat<br>\n" +#define USERLEAV " leaves the chat<br>\n" + +// several error messages which will apear by the clients. +#define E_NONICK "You need to specify a nick name<br><br>" +#define E_NOTONL "An error occured. Your nick is not online<br><br>" +#define E_ONLINE "The nick you have specified is already online. Try another nick.<br><br>" + +// all the custom messages for verbosity outputs. this messages may not +// be used for html-template value substituation except the CONTACT and +// DESCRIP variables. the verbosity output will appear in the standard +// output of the server. +// alphabetical ordered. +#define CFILEOK "Parsing config file " +#define CFILENO "Failed opening config file " +#define CONNECT "Receiving connection " +#define CONTACT "Contact: www.yChat.org, Mail@yChat.org " +#define DESCRIP "yChat++ Copyright (C) 2003 Paul C. Buetow, Volker Richer " +#define DOWNMSG "Shutting down " +#define LOGINPR "Login procedure succeeded for nick " +#define NEWROOM "Adding room " +#define REQUEST "Request string " +#define SEPERAT "----------------------------------------- " +#define SOCKCRT "Creating server socket " +#define SOCKERR "Could not create socket. Trying next port " +#define SOCKRDY "Server socket is ready. See port above " +#define STARTMS "Starting up " +#define TECACHE "Caching template " +#define THREADS "Starting thread job " +#define THREADE "Exiting thread job " +#define VERSION "Version: 0.2" + +#endif diff --git a/ychat-0.2/mutx.cpp b/ychat-0.2/mutx.cpp new file mode 100755 index 0000000..bbd5ced --- /dev/null +++ b/ychat-0.2/mutx.cpp @@ -0,0 +1,20 @@ +// class mutx implementation. + +#ifndef MUTX_CXX +#define MUTX_CXX + +#include "mutx.h" + +using namespace std; + +mutx::mutx() +{ + pthread_mutex_init( &mut_stdout, NULL ); +} + +mutx::~mutx() +{ + pthread_mutex_destroy( &mut_stdout ); +} + +#endif diff --git a/ychat-0.2/mutx.h b/ychat-0.2/mutx.h new file mode 100755 index 0000000..4f6c950 --- /dev/null +++ b/ychat-0.2/mutx.h @@ -0,0 +1,21 @@ +// class mutx declaration. + +#ifndef MUTX_H +#define MUTX_H + +#include "incl.h" + +using namespace std; + +class mutx +{ +public: + // this mutex is needed for sync stdout and sdterr of different threads. + pthread_mutex_t mut_stdout; + + // public methods. + explicit mutx( ); // simple constructor. + ~mutx( ); // simple constructor. +}; + +#endif diff --git a/ychat-0.2/name.cpp b/ychat-0.2/name.cpp new file mode 100755 index 0000000..3ef1280 --- /dev/null +++ b/ychat-0.2/name.cpp @@ -0,0 +1,30 @@ +// class name implementation. + +#ifndef NAME_CXX +#define NAME_CXX + +#include "name.h" + +using namespace std; + +name::name( string s_name ) +{ + set_name( s_name ); +} + +name::~name() +{ +} + +string +name::get_name() const +{ + return s_name; +} + +void +name::set_name( string s_name ) +{ + this->s_name = s_name; +} +#endif diff --git a/ychat-0.2/name.h b/ychat-0.2/name.h new file mode 100755 index 0000000..28a2f91 --- /dev/null +++ b/ychat-0.2/name.h @@ -0,0 +1,28 @@ +// class name declaration. + +#ifndef NAME_H +#define NAME_H + +#include "incl.h" + +using namespace std; + +class name +{ +protected: + // private members: + string s_name; // object's name. + +public: + // small inline methods: + virtual string get_name ( ) const; + virtual void set_name ( string s_name ); + + // public methods: + explicit name( ) { }; // a standard constructor. + explicit name( string s_name ); // a standard constructor. + + ~name(); +}; + +#endif diff --git a/ychat-0.2/pool.cpp b/ychat-0.2/pool.cpp new file mode 100755 index 0000000..503d0f7 --- /dev/null +++ b/ychat-0.2/pool.cpp @@ -0,0 +1,214 @@ +// class pool implementation. + +#ifndef POOL_CXX +#define POOL_CXX + +#include "pool.h" + +#include "CONF.h" +#include "MUTX.h" +#include "TOOL.h" +#include "thrd.h" + +using namespace std; + +pool::pool() +{ + i_thrd_pool_size = TOOL::string2int( CONF::get().get_val( "THRDPOOL" ) ); + i_thrd_pool_queue = TOOL::string2int( CONF::get().get_val( "THRDQUEU" ) ); + + tpool_init( &thread_pool, i_thrd_pool_size, i_thrd_pool_queue, 0 ); +} + +pool::~pool() +{ + // tpool_destroy ... +} + +void +pool::tpool_init( tpool_t *tpoolp, int num_worker_threads, int max_queue_size, int do_not_block_when_full ) +{ + int i, rtn; + tpool_t tpool; + + // allocate a pool data structure + if (( tpool = (tpool_t) malloc( sizeof( struct tpool ) ) ) == NULL ) + { + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cerr << "malloc" << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); + exit(-1); + } + + // initialize th fields + tpool->num_threads = num_worker_threads; + tpool->max_queue_size = max_queue_size; + tpool->do_not_block_when_full = do_not_block_when_full; + + if ( ( tpool->threads = (pthread_t*) malloc( sizeof( pthread_t ) *num_worker_threads ) ) == NULL ) + { + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cerr << "malloc" << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); + exit(-1); + } + + tpool->cur_queue_size = 0; + tpool->queue_head = NULL; + tpool->queue_tail = NULL; + tpool->queue_closed = 0; + tpool->shutdown = 0; + + if ( ( rtn = pthread_mutex_init( &(tpool->queue_lock), NULL ) ) != 0 ) + { + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cerr << "pthread_mutex_init " << strerror( rtn ) << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); + exit(-1); + } + + else if ( ( rtn = pthread_cond_init( &(tpool->queue_not_empty), NULL ) ) != 0 ) + { + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cerr << "pthread_cond_init " << strerror( rtn ) << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); + exit(-1); + } + + else if ( ( rtn = pthread_cond_init( &(tpool->queue_not_full), NULL ) ) != 0 ) + { + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cerr << "pthread_cond_init " << strerror( rtn ) << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); + exit(-1); + } + + else if ( ( rtn = pthread_cond_init( &(tpool->queue_empty), NULL ) ) != 0 ) + { + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cerr << "pthread_cond_init " << strerror( rtn ) << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); + exit(-1); + } + // create threads + for ( i = 0; i < num_worker_threads; i++ ) + pthread_create( &(tpool->threads[i]) , NULL, tpool_thread, (void*)tpool ); + + *tpoolp = tpool; +} + +void* +pool::tpool_thread( void* arg ) +{ + tpool_t tpool = (tpool_t) arg; + tpool_work_t *my_workp; + + while( true ) + { + pthread_mutex_lock( &(tpool->queue_lock) ); + + while ( (tpool->cur_queue_size == 0) && (!tpool->shutdown) ) + pthread_cond_wait( &(tpool->queue_not_empty), &(tpool->queue_lock) ); + + if (tpool->shutdown) + { + pthread_mutex_unlock( &(tpool->queue_lock) ); + pthread_exit( NULL ); + } + + my_workp = tpool->queue_head; + tpool->cur_queue_size--; + + if ( tpool->cur_queue_size == 0) + tpool->queue_head = tpool->queue_tail = NULL; + + else + tpool->queue_head = my_workp->next; + + if ( ( ! tpool->do_not_block_when_full ) && + ( tpool->cur_queue_size == ( tpool->max_queue_size - 1 ) ) ) + pthread_cond_signal( &(tpool->queue_not_full) ); + + if ( tpool->cur_queue_size == 0 ) + pthread_cond_signal( &(tpool->queue_empty) ); + + pthread_mutex_unlock( &(tpool->queue_lock) ); + (*(my_workp->routine))(my_workp->arg); + free((void*)my_workp); + } +} + +void pool::run_func( void *v_pointer ) +{ +#ifdef _VERBOSE + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cout << THREADS << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); +#endif + + // recasting the client thread object. + thrd *t = (thrd*) v_pointer; + + // start parsing the client request and sending response's back. + t-> run (); + + // close the client socket. + t->~thrd(); + + free(v_pointer); + +#ifdef _VERBOSE + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cout << THREADE << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); +#endif +} + +int +pool::tpool_add_work( tpool_t tpool, void(*routine)(void*), void* arg ) /// +{ + tpool_work_t *workp; + pthread_mutex_lock( &(tpool->queue_lock) ); + + if( ( tpool->cur_queue_size == tpool->max_queue_size ) && + tpool->do_not_block_when_full ) + { + pthread_mutex_unlock( &(tpool->queue_lock) ); + return -1; + } + + while( ( tpool->cur_queue_size == tpool->max_queue_size ) && + ( ! ( tpool->shutdown || tpool->queue_closed ) ) ) + pthread_cond_wait( &(tpool->queue_not_full), &(tpool->queue_lock) ); + + if( tpool->shutdown || tpool->queue_closed ) + { + pthread_mutex_unlock( &tpool->queue_lock ); + return -1; + } + + // allocate work structure: + workp = (tpool_work_t*) malloc( sizeof( tpool_work_t ) ); + + workp->routine = routine; + workp->arg = arg; + workp->next = NULL; + + if( tpool->cur_queue_size == 0 ) + { + tpool->queue_tail = tpool->queue_head = workp; + pthread_cond_signal( &(tpool->queue_not_empty) ); + } + + else + { + tpool->queue_tail->next = workp; + tpool->queue_tail = workp; + } + + tpool->cur_queue_size++; + pthread_mutex_unlock( &(tpool->queue_lock) ); + return 1; +} + +#endif diff --git a/ychat-0.2/pool.h b/ychat-0.2/pool.h new file mode 100755 index 0000000..358b79f --- /dev/null +++ b/ychat-0.2/pool.h @@ -0,0 +1,77 @@ +// class pool declaration. + +#ifndef POOL_H +#define POOL_H + +#include "incl.h" + +using namespace std; + +class pool +{ +private: + typedef struct tpool_work + { + void (*routine)(void*); /// + void *arg; + struct tpool_work *next; + } + tpool_work_t; + + typedef struct tpool + { + // pool characteristics: + int num_threads; + int max_queue_size; + int do_not_block_when_full; + + // pool state + pthread_t *threads; + int cur_queue_size; + + tpool_work_t *queue_head; + tpool_work_t *queue_tail; + + pthread_mutex_t queue_lock; + pthread_cond_t queue_not_empty; + pthread_cond_t queue_not_full; + pthread_cond_t queue_empty; + + int queue_closed; + int shutdown; + } + *tpool_t; + + int i_thrd_pool_size; + int i_thrd_pool_queue; + + tpool_t thread_pool; + + virtual void + tpool_init( tpool_t *tpoolp, int num_worker_threads, int max_queue_size, int do_not_block_when_full ); + + virtual int + tpool_add_work( tpool_t tpool, void(*routine)(void*), void* arg ); + +// virtual void +// tpool_destroy( tpool_t tpoolp, int finish ); + + static void* + tpool_thread( void* arg); + + static void + run_func( void *v_pointer ); + + // public methods: +public: + explicit pool( ); + ~pool(); + + // inline (speed)! + void run( void *arg ) + { + tpool_add_work( thread_pool, run_func, arg ); + } +}; + +#endif diff --git a/ychat-0.2/reqp.cpp b/ychat-0.2/reqp.cpp new file mode 100755 index 0000000..6cea6a9 --- /dev/null +++ b/ychat-0.2/reqp.cpp @@ -0,0 +1,224 @@ +// class reqp implementation. + +#ifndef REQP_CXX +#define REQP_CXX + +#include "reqp.h" +#include "CHAT.h" +#include "HTML.h" +#include "MUTX.h" +#include "sock.h" + +using namespace std; + +// inititialization of static members. +string reqp::HTTP_CODEOK = "HTTP/1.1 200 OK\n"; +string reqp::HTTP_SERVER = "Server: yChat (Unix)\n"; +string reqp::HTTP_CONTAC = "Contact: www.yChat.org\n"; +string reqp::HTTP_CACHEC = "Cash-control: no-cache\n"; +string reqp::HTTP_CONNEC = "Connection: keep-alive\n"; +string reqp::HTTP_COTYPE = "Content-Type: text/html\n\n"; + +reqp::reqp( ) +{ +} + +string +reqp::get_url( thrd* p_thrd, string s_req, map_string &map_params ) +{ + auto unsigned int pos; + string s_ret ( "" ); + string s_vars( "" ); + auto int i_request; + + i_request= ( s_req.find("GET",0) != string::npos ) ? RQ_GET : RQ_POST; + + pos = s_req.find( "HTTP", 0 ); + + if( i_request == RQ_GET ) + s_ret.append( s_req.substr( 5, pos-6 ) ); + else + s_ret.append( s_req.substr( 6, pos-7 ) ); + + // remove ".." from the request. + do + { + pos = s_ret.find( "../", 0 ); + + if ( pos == string::npos ) + break; + + s_ret.replace( pos, pos+2, "" ); + } + while( true ); + + // do not add the string behind "?" tp s_ret and add all params behind "?" to map_params. + if( i_request == RQ_GET ) + pos = s_ret.find( "?", 0 ); + else + pos = s_req.find("\r\n\r\n", 0); + + auto string s_params( "" ); + if ( pos != string::npos ) + { + if( i_request == RQ_GET ) + s_params.append( s_ret.substr( pos+1, s_ret.length() -pos-1 ) ); + + else + s_params = s_req.substr( pos+4, s_req.length() -pos-1 ); + + s_ret = s_ret.substr( 0, pos ); + } + + if ( i_request == RQ_POST && s_params.empty() ) + { + char c_req[READBUF]; + read ( p_thrd->get_sock() , c_req, READBUF ); + s_params = string( strstr( c_req, "event" ) ); + } + + auto unsigned int pos2; + do + { + pos = s_params.find( "=", 0 ); + if ( pos == string::npos ) + break; + + pos2 = s_params.find( "&", 0 ); + if ( pos2 == string::npos ) + { + auto string sValue( s_params.substr(pos+1, s_params.length()-pos-1) ); + auto string tmpstr( url_decode(sValue) ); + map_params[ s_params.substr( 0, pos ) ] = tmpstr; + break; + } + + auto string s_temp= s_params.substr( pos+1, pos2-pos-1 ); + map_params[ s_params.substr( 0, pos ) ] = url_decode(s_temp); + + s_params = s_params.substr( pos2+1, s_params.length()-pos2-1 ); + } + while( true ); + +#ifdef _VERBOSE + pthread_mutex_lock ( &MUTX::get().mut_stdout ); + cout << REQUEST << s_ret << endl; + pthread_mutex_unlock( &MUTX::get().mut_stdout ); +#endif + + map_params["request"] = s_ret; + + return s_ret; +} + +int +reqp::htoi(string *s) +{ + int value; + int c; + + c=s->c_str()[0]; + if(isupper(c)) + c=tolower(c); + + value=(c>='0' && c<='9'?c-'0':c-'a'+10)*16; + + c=s->c_str()[1]; + if(isupper(c)) + c=tolower(c); + + value+=c>='0' && c<='9'?c-'0':c-'a'+10; + return value; +} + +string +reqp::url_decode( string s_str ) +{ + auto string sDest=""; + int len = s_str.size(); + + for(int i=0;i<len;i++) + { + char ch = s_str.at(i); + if(ch=='+') + { + sDest+=" "; + } + else if(ch=='%') + { + auto string sTmp=s_str.substr(i+1,2); + ch=(char)htoi(&sTmp); + sDest+=ch; + i+=2; + + } + else + + sDest+=ch; + } + return sDest; +} + +string +reqp::get_from_header( string s_req, string s_hdr ) +{ + auto unsigned int pos[2]; + pos[0] = s_req.find( s_hdr, 0 ); + pos[1] = s_req.find( "\n", pos[0] ); + + auto int i_length = s_hdr.length(); + return s_req.substr( pos[0]+i_length, pos[1]-pos[0]-i_length-1 ); +} + +string +reqp::parse( thrd* p_thrd, string s_req, map_string &map_params ) +{ + // create the http header. + string s_rep( HTTP_CODEOK ); s_rep.append( HTTP_SERVER ); + s_rep.append( HTTP_CONTAC ); s_rep.append( HTTP_CACHEC ); + s_rep.append( HTTP_CONNEC ); s_rep.append( HTTP_COTYPE ); + + // store all request informations in map_params. store the url in + // map_params["request"]. + get_url( p_thrd, s_req, map_params ); + + // check the event variable. + string s_event( map_params["event"] ); + if ( ! s_event.empty() ) + { + // login procedure. + if ( s_event == "login" ) + { + CHAT::get().login( map_params ); + } + + else + { + bool b_found; + user* u_user = CHAT::get().get_user( map_params["nick"], b_found ); + + if ( ! b_found ) + { + map_params["INFO"] = E_NOTONL; + map_params["request"] = CONF::get().get_val( "STARTMPL" ); // redirect to the startpage. + } + + // if a message post. + else if ( s_event == "post" ) + CHAT::get().post( u_user, map_params ); + + // if a request for the online list of the active room. + else if ( s_event == "online" ) + HTML::get().online_list( u_user, map_params ); + } + } + + // parse and get the requested html-template and also use + // the values stored in map_params for %%KEY%% substituations. + s_rep.append( HTML::get().parse( map_params ) ); + + // return the parsed html-template. + return s_rep; +} + +#endif diff --git a/ychat-0.2/reqp.h b/ychat-0.2/reqp.h new file mode 100755 index 0000000..4e68a25 --- /dev/null +++ b/ychat-0.2/reqp.h @@ -0,0 +1,45 @@ +// class reqp declaration. this class parses the client requests. + +#ifndef REQP_H +#define REQP_H + +#define RQ_GET 1 +#define RQ_POST 2 + +#include <map> +#include "incl.h" +#include "thrd.h" + +using namespace std; + +typedef map<string, string, less<string> > map_string; + +class reqp +{ +private: + static string HTTP_CODEOK, + HTTP_CODENF, + HTTP_SERVER, + HTTP_CONTAC, + HTTP_CACHEC, + HTTP_CONNEC, + HTTP_COTYPE; + + // returns the request url from thr client's http request header + // until the first "?" and stores all request parameter values + // ( behind "?" ) into map_params. + virtual string get_url( thrd* p_thrd, string s_req, map_string &map_params ); + // returns a specific value of the client's http request header. + // ( s.t. like the User-Agent, Referer etc... ). + virtual string get_from_header( string s_req, string s_hdr ); + + virtual int htoi( string *s ); + +public: + // public methods. + explicit reqp( ); // simple constructor. + virtual string parse( thrd* p_thrd, string s_req, map_string &map_params ); + virtual string url_decode (string ); +}; + +#endif diff --git a/ychat-0.2/room.cpp b/ychat-0.2/room.cpp new file mode 100755 index 0000000..0e905e6 --- /dev/null +++ b/ychat-0.2/room.cpp @@ -0,0 +1,18 @@ +// class room implementation. + +#ifndef ROOM_CXX +#define ROOM_CXX + +#include "room.h" + +using namespace std; + +room::room( string s_name ) : name( s_name ) +{ +} + +room::~room() +{ +} + +#endif diff --git a/ychat-0.2/room.h b/ychat-0.2/room.h new file mode 100755 index 0000000..077fd28 --- /dev/null +++ b/ychat-0.2/room.h @@ -0,0 +1,34 @@ +// class room declaration. + +#ifndef ROOM_H +#define ROOM_H + +#include "incl.h" +#include "data.h" +#include "name.h" +#include "user.h" + +using namespace std; + +class room : public data<user>, public name +{ +private: + +public: + void add_user( user* p_user ) + { + p_user->set_p_room( this ); + add_elem( p_user ); + } + + user* get_user( string &s_name, bool &b_found ) + { + return static_cast<user*>( get_elem( s_name, b_found ) ); + } + + // public methods: + explicit room( string s_name ); // a constructor. + ~room(); // room destructor. +}; + +#endif diff --git a/ychat-0.2/sock.cpp b/ychat-0.2/sock.cpp new file mode 100755 index 0000000..c996ff5 --- /dev/null +++ b/ychat-0.2/sock.cpp @@ -0,0 +1,218 @@ +// class sock implementation. the multiplex socket implementation has been token from the +// GNU C Library Examples and modified in order to fit in here ( POSIX threads etc. ). + +#ifndef SOCK_CXX +#define SOCK_CXX + +#include <unistd.h> + +#include "sock.h" +#include "CHAT.h" +#include "CONF.h" +#include "MUTX.h" +#include "TOOL.h" + +#include "chat.h" +#include "user.h" + +using namespace std; + +sock::sock() +{ + this->b_run = true; + this->i_req = 0; + this->req_parser = new reqp(); + this->thrd_pool = new pool(); +} + +void +sock::chat_stream( int i_sock, map_string &map_params ) +{ + user* p_user = CHAT::get().get_user( map_params["nick"] ); + p_user->set_sock( i_sock ); + + string s_msg( "" ); + + pthread_mutex_lock ( &(p_user->mut_message) ); + + while( p_user->get_online() ) + { + pthread_cond_wait( &(p_user->cond_message), &(p_user->mut_message) ); + s_msg = p_user->get_mess( ); + if ( 0 > send( i_sock, s_msg.c_str(), s_msg.size(), 0 ) ) + p_user->set_online( false ); + } + + pthread_mutex_unlock( &(p_user->mut_message) ); + + // remove the user from its room. + string s_user( p_user->get_name() ); + p_user->get_p_room()->del_elem( s_user ); + + // post the room that the user has left the chat. + p_user->get_p_room()->msg_post( new string( p_user->get_name().append( USERLEAV ) ) ); + + p_user->~user(); +} + +int +sock::make_socket( uint16_t i_port ) +{ + int sock; + struct sockaddr_in name; + + // create the server socket. + sock = socket (PF_INET, SOCK_STREAM, 0); + if (sock < 0) + { + cerr << "Sock: socket error" << endl; + + if ( ++i_port > MAXPORT ) + exit(-1); + + cerr << SOCKERR << i_port << endl; + return make_socket( i_port ); + } + + // give the server socket a name. + name.sin_family = AF_INET; + name.sin_port = htons (i_port); + name.sin_addr.s_addr = htonl (INADDR_ANY); + int optval=1; + + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof(int)); + + if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) + { + cerr << "Sock: bind error" << endl; + + if ( ++i_port > MAXPORT ) + exit(-1); + + cout << SOCKERR << i_port << endl; + return make_socket( i_port ); + } + + return sock; +} + +int +sock::read_write( thrd* p_thrd, int i_sock ) +{ + char c_req[2048]; + + int i_bytes; + i_bytes = read (i_sock, c_req, 2048); + + if (i_bytes < 0) + { + cerr << "Sock: read error " << endl; + } + + else + { + // stores the request params. + map_string map_params; + + // get the s_rep ( HTML response which will be send imediatly to the client + // and fill map_params with request values. + auto string s_temp=(string)c_req; + + string s_rep = req_parser->parse( p_thrd, string( c_req ), map_params ); + + // send s_rep to the client. + send( i_sock, s_rep.c_str(), s_rep.size(), 0 ); + + // prove if this is a request for a chat stream! + if ( map_params["event"] == "stream" ) + chat_stream( i_sock, map_params ); + + return 0; + } + + return -1; +} + +int +sock::start() +{ + auto int i_port = TOOL::string2int( CONF::get().get_val( "SRVRPORT" ) ); + + int sock; + fd_set active_fd_set, read_fd_set; + int i; + struct sockaddr_in clientname; + size_t size; + +#ifdef _VERBOSE + cout << SOCKCRT << "localhost:" << i_port << endl; +#endif + + // create the server socket and set it up to accept connections. + sock = make_socket ( i_port ); + + if (listen (sock, 1) < 0) + { + cerr << "Sock: listen error" << endl; + exit( EXIT_FAILURE ); + } + +#ifdef _VERBOSE + cout << SOCKRDY << endl; +#endif + + // initialize the set of active sockets. + FD_ZERO (&active_fd_set); + FD_SET (sock, &active_fd_set); + + while( b_run ) + { + // block until input arrives on one or more active sockets. + read_fd_set = active_fd_set; + if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0) + { + cerr << "Sock: select error" << endl; + exit( EXIT_FAILURE ); + } + + // service all the sockets with input pending. + for ( i = 0; i < FD_SETSIZE; i++ ) + if ( FD_ISSET (i, &read_fd_set) ) + { + if ( i == sock ) + { + // connection request on original socket. + i_req++; + int new_sock; + size = sizeof (clientname); + new_sock = accept (sock, + (struct sockaddr *) &clientname, + &size); + + if (new_sock < 0) + { + cerr << "Sock: accept error" << endl; + close ( new_sock ); + } + +#ifdef _VERBOSE + cout << CONNECT << i_req << " " + << inet_ntoa( clientname.sin_addr ) + << ":" + << ntohs ( clientname.sin_port ) + << endl; +#endif + + FD_SET (new_sock, &active_fd_set); + } + + else + { + thrd_pool->run( (void*) new thrd( i ) ); + FD_CLR( i, &active_fd_set ); + } + } + } +} + +#endif diff --git a/ychat-0.2/sock.h b/ychat-0.2/sock.h new file mode 100755 index 0000000..abb5878 --- /dev/null +++ b/ychat-0.2/sock.h @@ -0,0 +1,51 @@ +// class sock declaration. + +#ifndef SOCK_H +#define SOCK_H + +#include <queue> +#include <arpa/inet.h> +#include <errno.h> +#include <netdb.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> + +#include "incl.h" +#include "pool.h" +#include "reqp.h" +#include "thrd.h" + +using namespace std; + +class sock +{ +private: + // total number of server requests. + unsigned long long int i_req; + + bool b_run; // true while socket manager is running. + reqp* req_parser; // parses the http requests from clients. + pool* thrd_pool; // the thread pool. + + // the chat stream there all the chat messages will sent through. + static void chat_stream( int i_sock, map_string &map_params ); + + // creates a server socket. + virtual int make_socket( uint16_t port ); + +public: + // small inline methods: + bool get_run() const { return b_run; } + bool set_run( bool b_run ) { this->b_run = b_run; } + + // public methods. + explicit sock( ); // simple constructor. + virtual int read_write( thrd* p_thrd, int filedes ); + virtual int start(); +}; + +#endif diff --git a/ychat-0.2/thrd.cpp b/ychat-0.2/thrd.cpp new file mode 100755 index 0000000..7c9be50 --- /dev/null +++ b/ychat-0.2/thrd.cpp @@ -0,0 +1,27 @@ +// class thrd implementation. + +#ifndef THRD_CXX +#define THRD_CXX + +#include "thrd.h" +#include "SOCK.h" + +using namespace std; + +thrd::thrd( int i_sock ) +{ + this->i_sock = i_sock; +} + +thrd::~thrd() +{ + shutdown ( get_sock() , 2 ); +} + +void +thrd::run() +{ + SOCK::get().read_write( this, i_sock ); +} + +#endif diff --git a/ychat-0.2/thrd.h b/ychat-0.2/thrd.h new file mode 100755 index 0000000..fecdb49 --- /dev/null +++ b/ychat-0.2/thrd.h @@ -0,0 +1,26 @@ +// class thrd declaration. + +#ifndef THRD_H +#define THRD_H + +#include "incl.h" + +using namespace std; + +class thrd +{ +private: + int i_sock; + +public: + + // small inline methods: + int get_sock() { return i_sock; } + + // public methods: + explicit thrd( int i_sock ); + ~thrd(); // destructor. + virtual void run(); +}; + +#endif diff --git a/ychat-0.2/todo.txt b/ychat-0.2/todo.txt new file mode 100755 index 0000000..47869ce --- /dev/null +++ b/ychat-0.2/todo.txt @@ -0,0 +1,7 @@ +mysql +tempid +commands +hash_maps +free pthread memory ( reusable thread pool ? ) +pthread mode 2 +semaphore sync ( ?? ) diff --git a/ychat-0.2/user.cpp b/ychat-0.2/user.cpp new file mode 100755 index 0000000..5a4068b --- /dev/null +++ b/ychat-0.2/user.cpp @@ -0,0 +1,143 @@ +// class user implementation. + +#ifndef USER_CXX +#define USER_CXX + +#include "user.h" +#include "CONF.h" +#include "TOOL.h" + +using namespace std; + +user::user( string s_name ) : name( s_name ) +{ + this -> b_online = true; + this -> l_time = TOOL::unixtime(); + this -> s_col1 = CONF::get().get_val( "USERCOL1" ); + + pthread_mutex_init( &mut_b_online, NULL); + pthread_mutex_init( &mut_i_sock , NULL); + pthread_mutex_init( &mut_l_time , NULL); + pthread_mutex_init( &mut_p_room , NULL); + pthread_mutex_init( &mut_s_mess , NULL); + pthread_cond_init ( &cond_message, NULL); + pthread_mutex_init( &mut_message , NULL); +} + +user::~user() +{ + pthread_mutex_destroy( &mut_b_online ); + pthread_mutex_destroy( &mut_i_sock ); + pthread_mutex_destroy( &mut_l_time ); + pthread_mutex_destroy( &mut_p_room ); + pthread_mutex_destroy( &mut_s_mess ); + pthread_cond_destroy ( &cond_message ); + pthread_mutex_destroy( &mut_message ); +} + +void +user::get_data( map_string *p_map_data ) +{ + string s_req = (*p_map_data)["!get"]; + + // get the nick and the color of the user. + if ( s_req == "nick" ) + (*p_map_data)[get_name()] = get_col1(); +} + +string +user::get_mess( ) +{ + string s_ret( "" ); + pthread_mutex_lock ( &mut_s_mess ); + s_ret.append( s_mess ); + s_mess = *new string(""); + pthread_mutex_unlock( &mut_s_mess ); + + return s_ret; +} + +bool +user::get_online( ) +{ + bool b_ret; + pthread_mutex_lock ( &mut_b_online ); + b_ret = b_online; + pthread_mutex_unlock( &mut_b_online ); + return b_ret; +} + +void +user::set_online( bool b_online ) +{ + pthread_mutex_lock ( &mut_b_online ); + this -> b_online = b_online; + pthread_mutex_unlock( &mut_b_online ); +} + +room* +user::get_p_room( ) +{ + room* p_return; + pthread_mutex_lock ( &mut_p_room ); + p_return = p_room; + pthread_mutex_unlock( &mut_p_room ); + return p_return; +} + +void +user::set_p_room( room* p_room ) +{ + pthread_mutex_lock ( &mut_p_room ); + this -> p_room = p_room; + pthread_mutex_unlock( &mut_p_room ); +} + +int +user::get_sock( ) +{ + int i_ret; + pthread_mutex_lock ( &mut_i_sock ); + i_ret = i_sock; + pthread_mutex_unlock( &mut_i_sock ); + return i_ret; +} + +void +user::set_sock( int i_sock ) +{ + pthread_mutex_lock ( &mut_i_sock ); + this -> i_sock = i_sock; + pthread_mutex_unlock( &mut_i_sock ); +} + +void +user::renew_stamp( ) +{ + pthread_mutex_lock ( &mut_l_time ); + l_time = TOOL::unixtime(); + pthread_mutex_unlock( &mut_l_time ); +} + +void +user::msg_post( string *p_msg ) +{ + pthread_mutex_lock ( &mut_s_mess ); + s_mess.append( *p_msg ); + pthread_mutex_unlock( &mut_s_mess ); + + pthread_cond_signal( &cond_message ); +} + +void +user::get_user_list( string &s_list, string &s_seperator ) +{ + s_list.append( "<font color=\"" ) + .append( get_col1() ) + .append( "\">" ) + .append( get_name() ) + .append( "</font>\n" ) + .append( s_seperator ); + +} +#endif diff --git a/ychat-0.2/user.h b/ychat-0.2/user.h new file mode 100755 index 0000000..1bdd79e --- /dev/null +++ b/ychat-0.2/user.h @@ -0,0 +1,79 @@ +// class user declaration. +#ifndef USER_H +#define USER_H + +#include "incl.h" +#include "name.h" + +using namespace std; + +class room; + +class user : public name +{ +private: + // private members: + bool b_away; // true if user is away. + bool b_online; // true if user is online. + int i_sock; // user's stream socket descriptor. + long l_time; // user's last activity time. + rang r_rang; // user's rang ( see enum rang @ globals.h ). + rang r_oldr; // user's previous rang. + string s_agnt; // user's http user agent. + string s_away; // user's last away message. + string s_col1; // user's nick color. + string s_mess; // message string which has to be sent to the user. + room* p_room; // pointer to the user's room. + + pthread_mutex_t mut_b_online; + pthread_mutex_t mut_i_sock; + pthread_mutex_t mut_l_time; + pthread_mutex_t mut_s_mess; + pthread_mutex_t mut_p_room; + +public: + pthread_cond_t cond_message; + pthread_mutex_t mut_message; + + // small inline methods: + string get_col1() const { return s_col1; } + void set_col1 ( string s_col1 ) { this -> s_col1 = s_col1; } + + rang get_rang ( ) const { return r_rang; } + void set_rang ( rang r_rang ) { r_oldr = this -> r_rang; + this -> r_rang = r_rang; } + + bool new_msgs ( ) { return s_mess.empty(); } + // public methods: + explicit user( string s_name ); // a standard constructor. + ~user(); // user destructor. + + // gets specific data of this user und stores it in + // (*p_map_string)["nick"]. this method will be used + // every time data has to be got from every user of a room + // or even of the system. + virtual void get_data( map_string *p_map_data ); + + virtual bool get_online(); + virtual void set_online( bool b_online ); + virtual room* get_p_room(); + virtual void set_p_room( room* p_room ); + virtual int get_sock ( ); + virtual void set_sock ( int i_sock ); + + + virtual void renew_stamp(); + + // gets the message and clears s_mess; + virtual string get_mess(); + + // Here are starting methods which are mainly needed by the data<type> class. + + // appends a string to s_mess including br. + virtual void msg_post( string *p_msg ); + + virtual void get_user_list( string &s_list, string &s_seperator ); + +}; + +#endif |
