165 Commits
0.1.0 ... 0.4.6

Author SHA1 Message Date
3071df227a fixed: find_ticket_value (in plugins/ticket/templates.cpp)
should find the first item (can be more than one item with the same 'param')

fixed: added sorting tickets params in ReadTicketParams() (in plugins/ticket/ticketinfo.cpp)

fixed: plugin should have its own 'PluginInfo info' struct
a plugin's function can call another plugin's functions

added: removing tickets files/images

added: removing threads

changed: rm function will call WINIX_FILE_REMOVED now when deleting directories





git-svn-id: svn://ttmath.org/publicrep/winix/trunk@710 e52654a7-88a9-db11-a3e9-0013d4bc506e
2011-01-23 23:23:24 +00:00
915cabdf97 changed: added Cur structure
we have there two pointers: 
 Request * request;
 Session * session;
these are the current request and the current session


the session GC was moved to SessionManager (was in SessionContainer)



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@708 e52654a7-88a9-db11-a3e9-0013d4bc506e
2011-01-23 14:15:30 +00:00
61ac29b2de added in ticket/templates.cpp binary search for tickets and tickets parameters
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@707 e52654a7-88a9-db11-a3e9-0013d4bc506e
2011-01-21 16:16:52 +00:00
ab84a5169e 'tickets' can use 'threads' now
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@706 e52654a7-88a9-db11-a3e9-0013d4bc506e
2011-01-20 18:37:51 +00:00
3fad25b8c8 moved some thread files to plugins/thread
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@705 e52654a7-88a9-db11-a3e9-0013d4bc506e
2011-01-05 21:44:19 +00:00
8154c403d8 we can create links (hard links, symbolic links) now
added winix functions: ln

winix function 'default' can be used without redirecting now

added new tickets types: TypeProgress, TypeString, TypeMultistring, TypeImages, TypeFiles
now tickets are combined with files
added winix functions: showtickets

fixed mountpoints:
when the default root mount was created its parameter table was empty
and it caused accessing to a non-existing objects

fixed logger:
modifiers (log1, log2, log3) were incorrectly treated
added modifier: log4 (debug info)

now we are moving threads to a new plugin 'thread'
created directory: plugins/thread
(not finished yet)




git-svn-id: svn://ttmath.org/publicrep/winix/trunk@704 e52654a7-88a9-db11-a3e9-0013d4bc506e
2011-01-05 21:24:11 +00:00
bb83aed20d changed cat template
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@703 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-12 09:41:20 +00:00
600c9fc907 Thumb thread should check the exit signal
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@701 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-12 09:25:36 +00:00
5d09eb149c added a special thread for making thumbnails (thumb.h thumb.cpp)
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@700 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-11 22:55:48 +00:00
e854fe3681 changed makefile
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@698 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-10 21:20:01 +00:00
36c8822e6c changed organization of static files
removed: item.auth item.auth_path
added:   item.file_path, item.file_fs, item.file_type
now the path to a static file is a relative path
added: thumbnails (not finished yet)
fixed: db didn't correctly return the number of deleted items /DelItem() method/




git-svn-id: svn://ttmath.org/publicrep/winix/trunk@696 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-10 21:07:01 +00:00
9b29cce1a4 added a special default function: "-"
the proper default function will be selected automatically


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@695 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-07 18:18:45 +00:00
508f06339e added to config: session_max
how many sessions can be: default 1000000 (one milion)


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@694 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-07 17:41:28 +00:00
0a9cdd2f15 added: gc for sessions (another thread)
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@693 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-07 12:52:52 +00:00
7f77b6e3ec added ezc function: user_is_in_all_groups
changed: ezc function user_is_in_group (we can provide more than one group now)


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@691 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-06 01:37:30 +00:00
9507b0b1ba changed Makefile
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@690 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-06 00:32:12 +00:00
ad9d6f4301 db: core/user table has only 'notify' column now (previous was cms_notify, thread_notify)
added: notifications for tickets (not finished yet)


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@688 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-06 00:25:46 +00:00
b721fb6860 changed path templatesnotifiy/ to notify/
i forgot to add a file: notify/notify.cpp


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@687 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-02 02:36:49 +00:00
5f46cd2ea5 moved: templatesnotify -> notify
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@686 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-02 02:16:11 +00:00
35efed9fef - now the mess with threads has gone away
- we have a class BaseThread -- this is a base class -- we can inherit from it when
  creating a new thread
- others treads are correctly stopped (when signal comes) -- pthread_join
- we have a special thread only for signals



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@685 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-12-02 01:02:02 +00:00
08e53919e2 changed: updated to the new ezc api, this with O(1) when looking for a specific ezc function
changed: sessions are deleted at the end of a request (and only a few sessions)
         other sessions will be deleted after a next request


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@684 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-11-25 22:42:24 +00:00
933c8841ff added: uptime winix function prints how many sessions there are
changed: functions for text/numbers conversions
         int Toi(const std::string & str,  int base = 10);
         int Toi(const std::wstring & str, int base = 10);
         int Toi(const char * str,         int base = 10);
         int Toi(const wchar_t * str,      int base = 10);

         long Tol(const std::string & str,  int base = 10);
         long Tol(const std::wstring & str, int base = 10);
         long Tol(const char * str,         int base = 10);
         long Tol(const wchar_t * str,      int base = 10);

         template<class CharType>
         bool Toa(unsigned long value, CharType * buffer, size_t buf_len, int base = 10);

         template<class CharType>
         bool Toa(long value, CharType * buffer, size_t buf_len, int base = 10);

         template<class CharType>
         bool Toa(unsigned int value, CharType * buffer, size_t buf_len, int base = 10);

         template<class CharType>
         bool Toa(int value, CharType * buffer, size_t buf_len, int base = 10);

         const wchar_t * Toa(unsigned int value,  int base = 10);
         const wchar_t * Toa(unsigned long value, int base = 10);
         const wchar_t * Toa(int value,  int base = 10);
         const wchar_t * Toa(long value, int base = 10);

         void Toa(int  value, std::string & res,  int base = 10, bool clear = true);
         void Toa(long value, std::string & res,  int base = 10, bool clear = true);
         void Toa(int  value, std::wstring & res, int base = 10, bool clear = true);
         void Toa(long value, std::wstring & res, int base = 10, bool clear = true);

added:   HtmlTextStream class (files htmltextstream.cpp htmltextstream.h in templates)
         this is a special stream for automatically escaping html tags
	     



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@682 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-11-25 01:34:46 +00:00
518281e101 fixed: when signal comes winix properly exits
fixed:   when winix exits the session data were not properly destroyed (memory leak)
         we should set request.session pointer to each session when deleting sessions
         from session_container
         the session data were not properly destroyed when winix checked for 
         outdated sessions (and when it was removing them)
fixed:   performance (memcpy used too often)
         in some places there were reserve method used (on std::wstring/std::string objects)
         especially in AssignString() method and TextStream<> object
         if we add a new string we should check the new size
         and only call reserve() if the new size will be greater than existing one
         (plus some constant)
changed: fcgi objects moved to App class (from Request)
         now we use thread safe methods (e.g. FCGX_Accept_r)
added:   log_plugin_call option to the config
         default: false
         when true winix log when a plugin function is called
added:   winix parameter 'nostat' for not calculating statistics
         (useful when making performance tests)


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@680 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-11-23 21:52:25 +00:00
515d4bab0d added ezc functions: winix_false, winix_true
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@679 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-11-22 01:12:46 +00:00
8e72a820dd added support for UTF-8
now the UTF-8 is a default charset


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@677 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-11-21 00:19:17 +00:00
f1f0fa34cb fixed: didn't compile
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@676 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-11-04 17:13:13 +00:00
5010ef93e8 added temporary debug info to Notify::ItemChanged() method
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@674 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-11-04 17:05:59 +00:00
e6679a3192 added a new winix function "vim" - an editor based on the WYMeditor
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@673 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-11-04 16:46:19 +00:00
7cf8d5d2d3 added: to htmlfilter: param tag has not an ending tag
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@672 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-10-25 18:00:23 +00:00
14198eca41 fixed: some log problems
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@671 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-10-24 19:31:43 +00:00
c6473f20dc now winix can demonize itself
parameter in the config: demonize (default: true)
 


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@669 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-10-24 19:26:54 +00:00
9c34cb5862 winix can drop privileges now (if started as the root)
added parameters to the config:
 user (string)
 group (string)
 additional_groups (bool)



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@668 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-10-24 17:49:38 +00:00
149fd1629f rm function can remove tickets now
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@667 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-10-23 23:51:44 +00:00
c48241f78a fixed: there were mktime() used on some dirs Items
so sometimes the time of the dir was changed

now for converting tm into time_t use:
time_t Time(const tm & par);
time_t Time(const tm * par);
tm     Time(time_t par);
from core/misc.h

now winix internally use GMT time
only when printing it is converted to local user time
temporarily all users use the same local time (config: time_zone_offset)
(only logs are genereted with local system time)

added to system:
time_t LocalTime(time_t gmt_time);
tm     LocalTime(const tm * ptm);
tm     LocalTime(const tm & ptm);
they convert GMT time to local user time




git-svn-id: svn://ttmath.org/publicrep/winix/trunk@666 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-10-23 23:12:47 +00:00
a1bee81a5b added 'stat' winix function
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@665 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-10-23 14:54:44 +00:00
1b053c03ba added: now plugin ticket uses a new horizontal table (plugins.ticket)
columns: dir_id, param, value
we are able to build complicated tickets 



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@664 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-10-19 00:31:20 +00:00
33057acd62 added ticket parser: plugins/ticket/ticketparser.h plugins/ticket/ticketparser.cpp
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@663 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-10-11 20:42:49 +00:00
07511a2eb0 fixed: DbBase::ConvertTime(tm) should not have been used in this way as it was
(it uses a static buffer)
       now DbTextStream can get tm struct so you don't have to use ConvertTime 


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@662 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-10-09 20:27:45 +00:00
69c634d53f added to core/misc:
bool EqualNoCase(const std::string & str1, const std::string & str2)


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@660 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-10-01 23:20:03 +00:00
7bc17a9202 fixed: ticket sets a default function only for directories
fixed: reading a new url and subject in Functions::ReadItem()
added: tickets are sorted now (by date)



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@659 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-09-30 20:58:20 +00:00
d94a08b991 moved: plugins/ticket/ticket.cpp -> plugins/ticket/templates.cpp
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@658 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-09-29 22:41:34 +00:00
a8b8c1feec tickets has been moved to a new plugin 'ticket'
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@657 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-09-29 21:24:34 +00:00
a589e5a090 added: TextStream a class similar to std::ostringstream
but with a Clear() method
       the dynamic allocated buffer can be easily reused
added: DbTextStream a special version of a stream
       used to create a database string query
       everything is escaped by default
added: DbBase a base class with some basic methods for communicating
       with the database
added: DbConn a class for managing connection to the database
changed: some refactoring in Db class       



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@655 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-09-18 00:51:12 +00:00
8b1db3304f creating winix/db directory (for the database class)
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@654 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-09-16 10:20:20 +00:00
23aedd68b0 changed: mount points
mount type and mount fs are of type 'int' now
they can be added by plugins


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@652 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-09-12 23:33:27 +00:00
f48f08a98b changed: notification's template
added: notifications in tickets


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@650 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-09-07 23:54:01 +00:00
81dd88d25a fixed: there was missing html/fun_editticket.html template
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@649 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-09-05 18:58:24 +00:00
c92081d6e1 added: to stats plugin: microsoft bing searcher
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@648 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-28 21:19:30 +00:00
d6e80f5a23 fixed: plugins path
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@647 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-17 23:48:42 +00:00
37cf71234c changed makefile
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@645 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-17 23:33:27 +00:00
3b655f39e1 added: plugins_dir to config
small changes in makefiles


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@643 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-17 22:32:47 +00:00
eec0ddf466 added: method ConfParser::UseEscapeChar(bool escape)
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@642 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-16 14:15:37 +00:00
ca4e53bb0f html code in editors (emacs, ckeditor...) is filtered now for normal users
(root is allowed to use any html code)


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@641 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-14 17:56:07 +00:00
d9f2e91806 removed some debug logs from emacs
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@640 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-14 17:07:13 +00:00
7bfed62526 emacs didn't correctly report errors from db
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@639 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-14 16:55:16 +00:00
b63ac98f40 now winix waites for the database to be ready (when the operating system starts)
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@638 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-14 16:23:18 +00:00
1e7d297c0e small changes in template winix function
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@637 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-14 14:45:25 +00:00
f3cd3b88b9 some improvement in templates
(now we have O(1) time for selecting the right html template)
added: winix function: template
for selecting a template for an item (file or dir)



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@636 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-13 20:04:57 +00:00
9a199cd834 part II of rewriting
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@635 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-12 19:10:12 +00:00
c3fac2e83f changed method: void PostMultiParser::ReadContentToFileLoop()
previous version was not clean


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@634 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-11 15:47:44 +00:00
c7f6d2727c fixed: PostMultiParser incorrectly logged the size of input items (those which were not files)
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@633 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-11 10:00:23 +00:00
9901c63ede removed some thread and ticket information from request
they are in FunThread and FunTicket classes now
added funtion FunUptime (I forgot about it)



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@631 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-10 20:43:38 +00:00
76897b8a83 I have forgotten to create classes: Ckeditor and Tinymce (in functions)
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@630 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-10 17:05:19 +00:00
217cf1420b the first part of reimplementing has been done
now we have app object and singletons are only: log logn plugin and app



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@628 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-10 16:12:50 +00:00
6897192364 added: [dir_last_url_is] to templates
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@626 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-08-02 18:36:17 +00:00
031ace3fe5 changed: the way how plugins work
all your plugin functions can have signature either:
void my_function(PluginInfo & info); or
void my_function();
only the main Init should have:
extern "C" void Init(PluginFunction & info);

added: directory 'plugins' for plugins
added: 'stats' plugin
		  


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@624 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-07-27 20:41:56 +00:00
e4683b9a05 fixed: in htmlfilter: <area> should be treated as single tag
changed: ConfParser is abble to recognize lists


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@623 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-07-21 17:24:16 +00:00
93da32cfb3 updated to the new version of ezc
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@621 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-07-19 23:07:34 +00:00
62a0e52092 added: progress bar (image) to tickets table
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@620 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-07-05 17:22:30 +00:00
262ba10443 small refactoring
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@619 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-07-05 15:21:06 +00:00
50cb88c5ed added: parameters consist of a name and a value now
sample: /dir/dir2/function/paramname:paramvalue
removed: TemplatesMisc namespace



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@618 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-07-04 20:27:14 +00:00
76e32703ac fixed: a mount parameter html_template() was not properly read when mountpoints were reloaded
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@617 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-07-01 15:40:18 +00:00
d9f5fbaf04 added: "edit" button on threads
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@616 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-06-30 19:56:32 +00:00
16bb238518 added: bbcode
files: core/bbcodeparser.h core/bbcodeparser.cpp


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@615 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-06-30 18:42:50 +00:00
759135fd7d struct Item has modification_user_id (long) now
this is the id of a user who has modified the item recently
this is only for information, persmissions don't use it


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@614 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-06-22 21:09:37 +00:00
56075857f2 debug
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@613 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-06-22 13:05:49 +00:00
8d3c7500d8 debugging info
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@612 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-06-22 13:01:56 +00:00
1e3f5e8695 added: mount option: html_template(file.html)
files: indexpatterns.h indexpatterns.cpp
removed: templates/index_root.html
        its content was moved to index.html


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@611 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-06-21 23:53:19 +00:00
08f5865c72 html templates
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@610 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-06-21 13:10:53 +00:00
ff3c141138 added: a new editor: tinymce (function tinymce)
added: html filter can check orphans: "i", "a", "o" ... in a text


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@607 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-06-20 22:47:24 +00:00
fe31e0e849 added: cp function for directories
added: emacs/mkdir uses group_id of the parent directory when creating new items
added: parameter 'dirls' to ls function


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@606 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-06-05 19:44:49 +00:00
2a26968c6c added: function cp (only for files)
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@605 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-06-03 17:38:18 +00:00
fe8774953a changed html templates
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@604 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-05-31 20:42:13 +00:00
4a7f036561 updated to new version of Ezc
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@602 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-05-30 21:07:46 +00:00
612f260938 added function: uname
added function: subject - for changing a subject


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@600 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-05-20 18:28:19 +00:00
2ad666d221 added: sessions data for plugins (plugindata.h plugindata.cpp)
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@598 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-05-04 21:58:22 +00:00
aff4cc516e added: 'rm' function can remove auth content now
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@597 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-03-15 17:09:45 +00:00
6fbcffe63b added: to the Item: auth_path - a path to a static file (if auth is different from auth_none)
added: function 'mv' (move)



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@596 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-03-15 01:47:26 +00:00
ebd868fa33 removed: Done class (core/done.h, core/done.cpp)
removed: from Session: done, done_status, timers



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@594 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-28 21:33:06 +00:00
71a63cc70e added: function adduser
changed: errors (removed enum, there are macros now)
added: error messages to locales (winix_err_NN)
removed: templates: err_abuse.html err_others.html


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@593 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-28 00:08:10 +00:00
3702efc5be added: parameter 'l' to 'ls' function
added: Db::ItemQuery struct for querying items
changed: some refactoring (renamed some config variables)




git-svn-id: svn://ttmath.org/publicrep/winix/trunk@589 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-22 22:52:09 +00:00
16e51cd4e5 added: to mount points: file systems
we have two file systems now:
       - simplefs - the files stored on the hard drive have the same structure as in the database (dir1/dir2/file)
       - hashfs - files are stored in special directories
extented: the mountparser can read file system 
added: function download
       this is a default function for items which have static content
  


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@588 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-18 23:30:22 +00:00
87747fab06 added: functions: chmod, chown
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@587 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-16 18:34:41 +00:00
4fe3d4339f added: parameter 'r' to priv function
all directories and files can be changed


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@586 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-16 00:37:00 +00:00
a276fb6b79 modified templates
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@585 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-15 18:22:16 +00:00
fa8d8f9ea0 fixed: Config::Text() returned a reference to a local variable (std::string)
added: 'static' directory with *.css and images
       we have a default layout
moved: locale from data to templates       
       notification templates have its own locale object
added: reload function reloades locale now too
added: 'nice' form of item_info in templates



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@582 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-15 00:31:14 +00:00
c58031cbf4 added static dir
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@581 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-14 14:28:43 +00:00
4aae12fc63 I forgot to commit loadavg.h and loadavg.cpp
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@579 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-13 20:14:44 +00:00
256a8fb5c5 added: calculation of load averages and requests per second
(uptime function shows it)


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@577 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-13 20:12:15 +00:00
3c5a7cd664 changed: upload function
select file type by the extension
         param: multi
fixed:   uptime function
         it showed incorrect uptime time (minuts were badly calculated)


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@575 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-12 23:16:13 +00:00
796985472a added to config: parameter static_auth_dir_tmp
with a path to directory for tmp files (for upload functino)



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@572 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-12 17:05:32 +00:00
7e0014865e added: loggin to upload.cpp
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@571 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-12 16:39:09 +00:00
cd74d1887a fixed: sprintf %d in uptime function
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@569 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-11 21:04:53 +00:00
adf36e71ce added: functions: ckeditor, uptime
added: for function: login - a html pattern for GET request


git-svn-id: svn://ttmath.org/publicrep/winix/trunk@567 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-11 20:56:52 +00:00
fc3c303d30 added: to templates: item_url_is and dir_last_url
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@566 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-08 20:02:16 +00:00
0e50977779 added: 'rm' function can work with tickets
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@565 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-02-06 14:08:44 +00:00
ed9feaf542 changed: log is saved after some requests (config: log_request value) (performance)
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@563 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-28 21:09:48 +00:00
09d427b4ba changed: rename cmslu to winix
changed: html templates are a part of winix now
         and the user can provide special html templates for its site
added:   locales
added:   html templates are using HtmlFilter now (locales)
changed: now we have html templates for each language



git-svn-id: svn://ttmath.org/publicrep/winix/trunk@560 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-28 15:39:01 +00:00
5dac8af300 renaming cmslu to winix
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@559 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-26 19:07:40 +00:00
1493a6180a moving html templates to cmslu
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@558 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-26 19:02:21 +00:00
848ddcebd7 fixed: not logged users cannot edit a ticket
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@557 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-25 07:27:18 +00:00
71763d340e fixed: not logged users are not allowed to remove anything
(temporarily - we're waiting for the sticky bit)


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@556 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-25 07:04:34 +00:00
89daf6489d added: issues ticket system
added functions: ticket, createticket, editticket
         (there is no 'rm' function working for tickets yet)
changed: mount parser and mount points
         now we have more parameters (arguments in parameters)
some refactoring in functions 'emacs' and 'mkdir'



git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@554 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-25 04:52:17 +00:00
356e93914b fixed: there was a wrong template used for 404 header
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@553 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-11 16:41:23 +00:00
5523d0c27a fixed: access to content type should not be checked when generating a page
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@552 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-11 15:09:31 +00:00
590a94523e fixed: content type was always 'formatted text' (in emacs when creating a new item)
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@551 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-11 14:59:19 +00:00
3c95b84633 added: item content type: raw
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@549 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-11 14:47:52 +00:00
59943c87cd added: default values for variables read from the config file
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@547 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-07 14:45:00 +00:00
3f9a46b1f7 added: static_auth_dir to config
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@545 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-06 19:36:29 +00:00
81faca041a added: parser for multipart forms, files: postmultiparser.h postmultiparser.cpp
added: function: upload




git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@543 e52654a7-88a9-db11-a3e9-0013d4bc506e
2010-01-06 19:17:53 +00:00
60fccea703 fixed: dots in url-es (now only one dot is available in the whole name and it cannot be only one dot ".")
added:   cmslu can act as an authorizer (fast cgi authorize role)
added:   Item::static_auth we can have additional static content on the file system
         this content is authorized through cmslu (fastcgi authorizer mode)
changed: some changes in config
changed: the way how the www server is using cmslu
         added new virtuals: static static_auth
changed: cmslu returns correct http headers (200, 404, 403)
changed: in cookie parser: we get the last cookie (if the server has more than one cookie with the same name)



git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@540 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-12-30 20:46:12 +00:00
118bf1fc65 added: exception for the Konqueror browser
it has a problem with deflate compression


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@539 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-12-19 19:46:15 +00:00
ce7ae3edd4 changed: notification times
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@536 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-12-09 00:52:00 +00:00
717eb526fb * added: class HTMLFilter
files: htmlfilter.h htmlfilter.cpp
         this is an html filter used to make the html output looking better
         this is a very lightweight filter
         (without using any dynamic memory - some memory is allocated only at the beginning - in ctors)
         this filter has O(n) complexity over the whole html string
* added: antyspamming method
         if the POST request is sent too fast after the GET
         it is treated as a spam
         only for no logged users and only in 'emacs' and 'createthread' functions
       


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@534 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-12-09 00:42:40 +00:00
9241fddb1e small changes in Makefile
now the binaries are in local 'bin' directory
(use make install)


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@532 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-12-04 05:03:44 +00:00
2dff0bed72 changed: SessionParser::ReadLong() can read negative values
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@531 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-11-21 00:08:08 +00:00
4827c116f0 added: 'remember me' flag when logging
added: the session file
       sessions can still be available between starting and stopping the cmslu system


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@529 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-11-20 23:09:52 +00:00
848afac803 removed: hidden variable 'old_url' in emacs template
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@527 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-11-18 01:58:38 +00:00
13b0204427 I have forgotten to add templates/rebus.cpp to the repository
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@525 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-11-17 01:07:29 +00:00
dc5f002de3 refactoring
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@523 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-11-17 01:04:01 +00:00
2ca44ec361 added: Rebus
(when no logged user wants to send a message then he is asked a question)


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@521 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-11-16 23:36:38 +00:00
c62d48160a fixed: the core didn't test for special folder when system was running
(now mkdir addes correctly special folders)
added: function 'reload'
       param: 'templates' - reloading templates


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@519 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-11-16 17:43:23 +00:00
9129f1b82a added: mount points are read from db: /etc/fstab
changed: mount points parser allows empty lines (with some white characters)


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@518 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-11-15 23:55:11 +00:00
378cfc0c3d added: plugin mechanism
files: core/plugin.h core/plugin.cpp core/pluginmsg.h
added: directory 'main' with main.cpp (moved from 'core' directory)
changed: the way of building
       nearly everything is in cmslu.so
       only main() is in cmslu and is dynamically linked with cmslu.so



git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@516 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-11-13 20:40:11 +00:00
7db71d43e0 added: acceptbaseparser.h acceptbaseparser.cpp
class AcceptBaseParser for parsing http accept* headers
added: acceptencodingparser.h
       class AcceptEncodingParser for parsing HTTP_ACCEPT_ENCODING header
added: compresion only when HTTP_ACCEPT_ENCODING has 'deflate'
       and the browser is not the Internet Explorer


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@515 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-10-08 17:59:10 +00:00
85b678a8fb added: notifications to users' emails
(core/notify.h core/notify.cpp)
       templatesnotify directory
       all notifications are managed by a second thread


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@512 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-09-30 22:31:20 +00:00
9902ce2b78 added: support for output compression
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@511 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-09-21 23:05:05 +00:00
394c7b22a2 changed: mount points
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@508 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-06-07 22:17:07 +00:00
f99c993d96 added: column 'guest_name' to 'item' table
used when user_id is -1
added: mount parameters: thread_with_info, thread_with_header
added: function rm can remove threads



git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@506 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-06-07 02:40:27 +00:00
1eb42446f8 added: forum
added: mount params can have arguments (in parentheses)
added: mount params: withheader, withinfo, restrictcreatethread, only_root_can_remove,
       can_use_emacs_on(level), can_use_mkdir_on(level), 
added: table Item has 'subject' column now
removed: column 'subject' from table Content




git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@505 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-06-05 20:29:06 +00:00
3d001e7458 added: macro APPPREPARE
void AppFunction(int code);



git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@503 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-05-21 19:27:16 +00:00
2dd3fc7df8 changed: the way of building
core.a content.a templates.a confparser.a have gone away
	 there is only: cmslu.a now (in the global directory 'cmslu')
changed: the way of building
         in Makefile(s) we dont longer use explicitly a variable 'o = file1.o file2.o...'
	 it was put into Makefile.o.dep and is generated automatically 
         when 'make depend' is invoked
changed: some #include "..." directives were put from *.h to *.cpp files
         fewer dependences


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@501 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-04-21 20:50:55 +00:00
f46677dfc0 added: mount points have parameters now
added: to the database: table 'thread'



git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@499 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-04-20 23:49:28 +00:00
e94ccc86f8 fixed: a small problem in mountparser (it coused core dumped when there was a wrong mount point supplied)
fixed: 'default' funtion can take a directory now (there was an error early)


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@497 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-04-20 21:10:31 +00:00
e778903dab added: put info about logging out a user (to 'last' table) (when a session expires)
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@496 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-04-20 20:22:35 +00:00
a1ea298a43 added: mount points
(reading /etc/fstab from db not working yet)
       core/mount.h
       core/mountparser.h
       core/mountparser.cpp
       core/mounts.h
       core/mounts.cpp
       content/thread.cpp
       content/createthread.cpp
       templates/thread.cpp       



git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@495 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-04-19 22:13:21 +00:00
7a4a8e0fe2 added: container LastContainer (lastcontainer.h lastcontainer.cpp)
it consists of last logged users
added: function 'last'


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@492 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-04-16 01:59:42 +00:00
bbaefd0f77 added: date_creation and date_modification to items
changed: function 'run' is using a template: fun_run.html
         there is: [item_run] called from this template


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@489 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-03-22 23:54:15 +00:00
951d0e8653 changed: DirContainer - uses std::list instead of std::vector as the main container
we do not have to rebuild indexes after deleting some items
added:   DirContainer::DelById(long id)
changed: Dirs::CheckRootDir() addes the root dir if there is no one
added:   Dirs::DeleteDir(long id) - deletes specified directory (and its contents)
         (from the cache and the database)
added:   Db::DelDirById(long id) - deletes a dir from the database 
         and its first children
added:   standard function rm can delete directories


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@487 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-02-06 13:12:03 +00:00
7d73d048c8 added: SessionContainer special container used by SessionManager
sessions are indexed by id and time (last used time)
changed: old sessions are deleted
       parameter: session_max_iddle in the config file
added: function 'who'


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@483 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-01-31 06:53:36 +00:00
a48766871d fixed: the way AppDb works (pg_conn and Connect method)
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@482 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-01-27 18:43:44 +00:00
406cb4a619 changed: not logging (headers and body)
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@480 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-01-26 21:21:07 +00:00
9418cc7a69 default.item has to be default.cpp
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@479 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-01-26 21:08:42 +00:00
20f6fbcf84 changed: the way of building the cmslu
main Makefile is in an application directory
         in cmslu/ there are only libraries:
         core.a content.a confparser.a templates.a
added:   macros APPTEMPLATES APPFUNCTIONS
         defined in the application's Makefile
added:   PatternCacher
added:   cmslu function 'run'
         files which have exec permissions
         can be run (run is a default function)
         after read from the database the content is parsed
         into Ezc::Pattern object, this object is then cached
         in PatternCacher
added:   FunctionCodeParser - will be used to parse the code
         from standard functions (ls/cat/...)


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@475 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-01-26 20:49:28 +00:00
327f18525c changed: cmslu building
Makefile from cmslu/ builds only: confparser.a content.a core.a templates.a
         the proper *.fcgi file is created from an application
changed: all cmslu functions have english names (ls, emacs, etc)
fixed:   function: login/logout are placed where there are permissions


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@474 e52654a7-88a9-db11-a3e9-0013d4bc506e
2009-01-14 20:11:12 +00:00
8a0ea59c77 added: function: default
changes the default item in a directory


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@473 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-12-31 18:28:12 +00:00
f6ad846927 I forgot to commit content/mkdir.cpp
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@472 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-12-31 13:40:23 +00:00
114b5724f8 added: function: mkdir
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@471 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-12-31 13:36:46 +00:00
3e328932fc added: created directory 'content' which has Content:: files
added:   created directory 'templates' which has Templates:: and TemplatesFunctions:: files
changed: content.cpp split into many files (directory 'content')
changed: templates.cpp split into many files (directory 'templates')
added:   full permissions
changed: building of the program (GNU make is used now)
         Makefile and Makefile.dep added into directories
added:   a parser 'FunctionParser'
         is used to parse the GET string
         it recognizes directories, items, functions, functions parameters
added:   other classes: Function, Functions 
added:   function: ls, privileges
changed: function 'id' to 'node'
changed: version: to 0.2.0
added/changed: a lot of work have been done


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@469 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-12-30 01:05:03 +00:00
fac60a197b changed: there is one dir called root (has parent_id -1)
(we have an owner, group, privileges etc of the root dir)
         the root.id of course is not -1 


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@468 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-12-22 16:03:03 +00:00
55cd813141 added: privileges (user, groups, permissions)
(not finished yet)
       classes: User, Group, Users, Groups, UGContainer
changed: Dir class into Dirs


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@467 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-12-21 21:17:09 +00:00
86f28faf8d changed: db: table item: url_subject into url
changed: item.url_subject into item.url
changed: a new table: content
         with: id, subject, content, content_type
         (those from the item table)
         it helps to create hard links


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@466 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-12-14 05:28:28 +00:00
023faa66fc added: config: base_url_redirect
when true the server checks whether HTTP_HOST environment variable
       is the same as base_url from the config (of course without the 'http://' part
       and the last slash) - if it's not the same then the server
       redirects you into a new location base_url+REQUEST_URI
changed: variables env_* from Request are never null (after Request::Read())
       if the server didn't set such a variable it will be pointing into an empty string "\0"


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@465 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-12-12 03:11:29 +00:00
3462cdf827 I forgot to add config.h and config.cpp into the repository
git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@464 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-12-11 02:48:25 +00:00
8aab988752 added: program reads its configuration from a config file
added: confparser directory and confparser.h and confparser.cpp
       class ConfParser used to parse a config file
       this is a generic parser, can be used by another project
added: config.h, config.cpp
       class Config used for assigning values from 
       a config file into the data object
added: function for signals: SIGINT, SIGHUP
       after receiving SIGHUP the program will read
       its config file again


git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@463 e52654a7-88a9-db11-a3e9-0013d4bc506e
2008-12-11 02:46:16 +00:00
354 changed files with 44524 additions and 3722 deletions

118
Makefile
View File

@@ -1,46 +1,92 @@
CC = g++
o = templates.o log.o requestcontroller.o main.o misc.o db.o session.o request.o content.o sessionmanager.o httpsimpleparser.o data.o dir.o error.o done.o dircontainer.o ezc.o
CFLAGS = -Wall -pedantic -g -I/usr/local/include -L/usr/local/lib
name = cmslu.fcgi
# Makefile for GNU make
ifndef CXX
CXX = g++
endif
all: $(name) $(mod_cms)
$(name): $(o)
g++ -o $(name) $(CFLAGS) $(o) -lfcgi -lpq
.SUFFIXES: .cpp .o
.cpp.o:
$(CC) -c $(CFLAGS) $<
ifndef CXXFLAGS
CXXFLAGS = -fPIC -Wall -pedantic -O2 -I/usr/local/include -I/home/tomek/roboczy/winix -I/home/tomek/roboczy/ezc/src -L/usr/local/lib -DEZC_USE_WINIX_LOGGER
endif
templates.o: core/templates.cpp core/templates.h core/../../ezc/src/ezc.h core/data.h core/misc.h core/log.h core/item.h core/error.h core/dir.h core/db.h core/dircontainer.h core/request.h core/requesttypes.h core/session.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h
log.o: core/log.cpp core/log.h
requestcontroller.o: core/requestcontroller.cpp core/requestcontroller.h core/data.h core/misc.h core/log.h core/item.h core/error.h core/dir.h core/db.h core/dircontainer.h core/request.h core/requesttypes.h core/session.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h core/content.h core/templates.h core/../../ezc/src/ezc.h core/sessionmanager.h
main.o: core/main.cpp core/requestcontroller.h core/data.h core/misc.h core/log.h core/item.h core/error.h core/dir.h core/db.h core/dircontainer.h core/request.h core/requesttypes.h core/session.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h core/content.h core/templates.h core/../../ezc/src/ezc.h core/sessionmanager.h
misc.o: core/misc.cpp core/misc.h core/log.h core/item.h
db.o: core/db.cpp core/db.h core/log.h core/item.h core/misc.h core/error.h core/dircontainer.h
session.o: core/session.cpp core/session.h core/requesttypes.h core/error.h core/log.h core/item.h core/done.h
request.o: core/request.cpp core/request.h core/requesttypes.h core/log.h core/session.h core/error.h core/item.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h
content.o: core/content.cpp core/content.h core/templates.h core/../../ezc/src/ezc.h core/data.h core/misc.h core/log.h core/item.h core/error.h core/dir.h core/db.h core/dircontainer.h core/request.h core/requesttypes.h core/session.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h
sessionmanager.o: core/sessionmanager.cpp core/sessionmanager.h core/request.h core/requesttypes.h core/log.h core/session.h core/error.h core/item.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h core/data.h core/misc.h core/dir.h core/db.h core/dircontainer.h
httpsimpleparser.o: core/httpsimpleparser.cpp core/httpsimpleparser.h
data.o: core/data.cpp core/data.h core/misc.h core/log.h core/item.h core/error.h core/dir.h core/db.h core/dircontainer.h
dir.o: core/dir.cpp core/dir.h core/item.h core/error.h core/log.h core/db.h core/misc.h core/dircontainer.h
error.o: core/error.cpp core/error.h core/log.h
done.o: core/done.cpp core/done.h
dircontainer.o: core/dircontainer.cpp core/dircontainer.h core/item.h core/log.h
export CXX
export CXXFLAGS
ezc.o: ../ezc/src/ezc.cpp ../ezc/src/ezc.h
all: winix
winix: FORCE
@cd core ; $(MAKE) -e
@cd db ; $(MAKE) -e
@cd functions ; $(MAKE) -e
@cd templates ; $(MAKE) -e
@cd notify ; $(MAKE) -e
@cd plugins/stats ; $(MAKE) -e
@cd plugins/thread ; $(MAKE) -e
@cd plugins/ticket ; $(MAKE) -e
@cd ../ezc/src ; $(MAKE) -e
$(CXX) -shared -o winix.so $(CXXFLAGS) core/*.o db/*.o functions/*.o templates/*.o notify/*.o ../ezc/src/ezc.a -lfcgi -lpq -lz -lpthread -lfetch
@cd main ; $(MAKE) -e
# use the full path with winix.so
$(CXX) -o winix $(CXXFLAGS) main/*.o /home/tomek/roboczy/winix/winix.so
clean:
rm -f *.o
rm -f $(name)
@cd core ; $(MAKE) -e clean
@cd db ; $(MAKE) -e clean
@cd functions ; $(MAKE) -e clean
@cd templates ; $(MAKE) -e clean
@cd notify ; $(MAKE) -e clean
@cd plugins/stats ; $(MAKE) -e clean
@cd plugins/thread ; $(MAKE) -e clean
@cd plugins/ticket ; $(MAKE) -e clean
@cd ../ezc/src ; $(MAKE) -e clean
@cd main ; $(MAKE) -e clean
rm -f winix.so
rm -f winix
FORCE:
depend:
@cd core ; $(MAKE) -e depend
@cd db ; $(MAKE) -e depend
@cd functions ; $(MAKE) -e depend
@cd templates ; $(MAKE) -e depend
@cd notify ; $(MAKE) -e depend
@cd plugins/stats ; $(MAKE) -e depend
@cd plugins/thread ; $(MAKE) -e depend
@cd plugins/ticket ; $(MAKE) -e depend
@cd ../ezc/src ; $(MAKE) -e depend
@cd main ; $(MAKE) -e depend
install: all
# binaries
mkdir -p /usr/local/winix/bin
cp winix.so /usr/local/winix/bin
# use the full path with winix.so (we have to recompile winix with a new path to winix.so)
$(CXX) -o /usr/local/winix/bin/winix $(CXXFLAGS) main/*.o /usr/local/winix/bin/winix.so
# html templates
mkdir -p /usr/local/winix/html
cp -rf html/ /usr/local/winix/html/
find /usr/local/winix/html/ -type d -name ".svn" | xargs -I foo rm -fr foo
# txt templates
mkdir -p /usr/local/winix/txt
cp -rf txt/ /usr/local/winix/txt/
find /usr/local/winix/txt/ -type d -name ".svn" | xargs -I foo rm -fr foo
# locales
mkdir -p /usr/local/winix/locale
cp -rf locale/ /usr/local/winix/locale/
find /usr/local/winix/locale/ -type d -name ".svn" | xargs -I foo rm -fr foo
# plugins
mkdir -p /usr/local/winix/plugins
find plugins/ -name "*.so" | xargs -I foo cp foo /usr/local/winix/plugins/
# removed provileges for others
find /usr/local/winix -exec chmod o-r,o-x,o-w "{}" "+"

22
core/Makefile Executable file
View File

@@ -0,0 +1,22 @@
include Makefile.o.dep
all: $(o)
.SUFFIXES: .cpp .o
.cpp.o:
$(CXX) -c $(CXXFLAGS) $<
depend:
makedepend -Y. -I.. -I../../ezc/src -f- *.cpp > Makefile.dep
echo -n "o = " > Makefile.o.dep
ls -1 *.cpp | xargs -I foo echo -n foo " " | sed -E "s/([^\.]*)\.cpp[ ]/\1\.o/g" >> Makefile.o.dep
clean:
rm -f *.o
include Makefile.dep

396
core/Makefile.dep Executable file
View File

@@ -0,0 +1,396 @@
# DO NOT DELETE
acceptbaseparser.o: acceptbaseparser.h
app.o: app.h config.h confparser.h htmlfilter.h system.h dirs.h item.h
app.o: dircontainer.h ../db/db.h ../db/dbbase.h ../db/dbconn.h
app.o: ../db/dbtextstream.h ../core/textstream.h misc.h ../core/error.h log.h
app.o: textstream.h ../db/dbitemquery.h ../core/item.h ../db/dbitemcolumns.h
app.o: ../core/user.h ../core/group.h ../core/dircontainer.h
app.o: ../core/ugcontainer.h request.h requesttypes.h error.h
app.o: ../templates/htmltextstream.h ../notify/notify.h
app.o: ../notify/notifypool.h ../templates/locale.h ../core/confparser.h
app.o: ../templates/misc.h ../templates/localefilter.h ../templates/locale.h
app.o: ../../ezc/src/ezc.h ../../ezc/src/utf8.h ../../ezc/src/generator.h
app.o: ../../ezc/src/pattern.h ../../ezc/src/functions.h
app.o: ../../ezc/src/funinfo.h ../../ezc/src/stringconv.h
app.o: ../templates/htmltextstream.h ../notify/notifythread.h
app.o: ../core/basethread.h synchro.h ../notify/templatesnotify.h
app.o: ../core/config.h ../core/users.h user.h ugcontainer.h lastcontainer.h
app.o: cur.h session.h plugindata.h rebus.h mounts.h mount.h mountparser.h
app.o: users.h groups.h group.h loadavg.h thumb.h basethread.h
app.o: sessionmanager.h sessioncontainer.h ../functions/functions.h
app.o: ../functions/functionbase.h ../core/request.h ../core/system.h
app.o: ../core/synchro.h ../functions/functionparser.h ../core/cur.h
app.o: ../functions/adduser.h ../functions/cat.h ../functions/chmod.h
app.o: ../functions/privchanger.h ../functions/chown.h
app.o: ../functions/ckeditor.h ../functions/cp.h ../functions/default.h
app.o: ../functions/download.h ../functions/emacs.h ../functions/last.h
app.o: ../functions/login.h ../functions/logout.h ../functions/ln.h
app.o: ../functions/ls.h ../functions/mkdir.h ../functions/mv.h
app.o: ../functions/node.h ../functions/priv.h ../functions/reload.h
app.o: ../functions/rm.h ../functions/run.h ../functions/specialdefault.h
app.o: ../functions/stat.h ../functions/subject.h ../functions/template.h
app.o: ../functions/tinymce.h ../functions/uname.h ../functions/upload.h
app.o: ../functions/uptime.h ../functions/who.h ../functions/vim.h
app.o: ../core/htmlfilter.h ../templates/templates.h
app.o: ../templates/patterncacher.h ../templates/ckeditorgetparser.h
app.o: ../core/httpsimpleparser.h ../core/log.h ../templates/indexpatterns.h
app.o: ../core/sessionmanager.h compress.h getparser.h httpsimpleparser.h
app.o: postparser.h cookieparser.h postmultiparser.h acceptencodingparser.h
app.o: acceptbaseparser.h plugin.h pluginmsg.h
basethread.o: basethread.h log.h textstream.h
bbcodeparser.o: bbcodeparser.h htmlfilter.h
compress.o: compress.h log.h textstream.h
config.o: config.h confparser.h htmlfilter.h log.h textstream.h plugin.h
config.o: pluginmsg.h plugindata.h request.h requesttypes.h item.h error.h
config.o: ../templates/htmltextstream.h ../core/textstream.h misc.h system.h
config.o: dirs.h dircontainer.h ../db/db.h ../db/dbbase.h ../db/dbconn.h
config.o: ../db/dbtextstream.h ../core/error.h ../db/dbitemquery.h
config.o: ../core/item.h ../db/dbitemcolumns.h ../core/user.h ../core/group.h
config.o: ../core/dircontainer.h ../core/ugcontainer.h ../notify/notify.h
config.o: ../notify/notifypool.h ../templates/locale.h ../core/confparser.h
config.o: ../templates/misc.h ../templates/localefilter.h
config.o: ../templates/locale.h ../../ezc/src/ezc.h ../../ezc/src/utf8.h
config.o: ../../ezc/src/generator.h ../../ezc/src/pattern.h
config.o: ../../ezc/src/functions.h ../../ezc/src/funinfo.h
config.o: ../../ezc/src/stringconv.h ../templates/htmltextstream.h
config.o: ../notify/notifythread.h ../core/basethread.h synchro.h
config.o: ../notify/templatesnotify.h ../core/config.h ../core/users.h user.h
config.o: ugcontainer.h lastcontainer.h cur.h session.h rebus.h mounts.h
config.o: mount.h mountparser.h users.h groups.h group.h loadavg.h thumb.h
config.o: basethread.h sessionmanager.h sessioncontainer.h
config.o: ../functions/functions.h ../functions/functionbase.h
config.o: ../core/request.h ../core/system.h ../core/synchro.h
config.o: ../functions/functionparser.h ../core/cur.h ../functions/adduser.h
config.o: ../functions/cat.h ../functions/chmod.h ../functions/privchanger.h
config.o: ../functions/chown.h ../functions/ckeditor.h ../functions/cp.h
config.o: ../functions/default.h ../functions/download.h ../functions/emacs.h
config.o: ../functions/last.h ../functions/login.h ../functions/logout.h
config.o: ../functions/ln.h ../functions/ls.h ../functions/mkdir.h
config.o: ../functions/mv.h ../functions/node.h ../functions/priv.h
config.o: ../functions/reload.h ../functions/rm.h ../functions/run.h
config.o: ../functions/specialdefault.h ../functions/stat.h
config.o: ../functions/subject.h ../functions/template.h
config.o: ../functions/tinymce.h ../functions/uname.h ../functions/upload.h
config.o: ../functions/uptime.h ../functions/who.h ../functions/vim.h
config.o: ../core/htmlfilter.h ../templates/templates.h
config.o: ../templates/patterncacher.h ../templates/ckeditorgetparser.h
config.o: ../core/httpsimpleparser.h ../core/log.h
config.o: ../templates/indexpatterns.h ../core/sessionmanager.h
confparser.o: confparser.h misc.h item.h ../../ezc/src/utf8.h
dircontainer.o: dircontainer.h item.h log.h textstream.h
dirs.o: dirs.h item.h dircontainer.h ../db/db.h ../db/dbbase.h ../db/dbconn.h
dirs.o: ../db/dbtextstream.h ../core/textstream.h misc.h ../core/error.h
dirs.o: log.h textstream.h ../db/dbitemquery.h ../core/item.h
dirs.o: ../db/dbitemcolumns.h ../core/user.h ../core/group.h
dirs.o: ../core/dircontainer.h ../core/ugcontainer.h request.h requesttypes.h
dirs.o: error.h config.h confparser.h htmlfilter.h
dirs.o: ../templates/htmltextstream.h ../notify/notify.h
dirs.o: ../notify/notifypool.h ../templates/locale.h ../core/confparser.h
dirs.o: ../templates/misc.h ../templates/localefilter.h ../templates/locale.h
dirs.o: ../../ezc/src/ezc.h ../../ezc/src/utf8.h ../../ezc/src/generator.h
dirs.o: ../../ezc/src/pattern.h ../../ezc/src/functions.h
dirs.o: ../../ezc/src/funinfo.h ../../ezc/src/stringconv.h
dirs.o: ../templates/htmltextstream.h ../notify/notifythread.h
dirs.o: ../core/basethread.h synchro.h ../notify/templatesnotify.h
dirs.o: ../core/config.h ../core/users.h user.h ugcontainer.h lastcontainer.h
dirs.o: cur.h session.h plugindata.h rebus.h
groups.o: groups.h group.h ugcontainer.h ../db/db.h ../db/dbbase.h
groups.o: ../db/dbconn.h ../db/dbtextstream.h ../core/textstream.h misc.h
groups.o: item.h ../core/error.h log.h textstream.h ../db/dbitemquery.h
groups.o: ../core/item.h ../db/dbitemcolumns.h ../core/user.h ../core/group.h
groups.o: ../core/dircontainer.h ../core/ugcontainer.h
htmlfilter.o: htmlfilter.h
httpsimpleparser.o: httpsimpleparser.h
item.o: item.h misc.h
lastcontainer.o: lastcontainer.h log.h textstream.h misc.h item.h
loadavg.o: loadavg.h log.h textstream.h
log.o: log.h textstream.h ../../ezc/src/utf8.h
misc.o: misc.h item.h log.h textstream.h ../templates/templates.h
misc.o: ../../ezc/src/ezc.h ../../ezc/src/utf8.h ../../ezc/src/generator.h
misc.o: ../../ezc/src/pattern.h ../../ezc/src/functions.h
misc.o: ../../ezc/src/funinfo.h ../../ezc/src/stringconv.h
misc.o: ../templates/patterncacher.h ../core/item.h
misc.o: ../templates/ckeditorgetparser.h ../core/httpsimpleparser.h
misc.o: ../core/log.h ../templates/indexpatterns.h
misc.o: ../templates/localefilter.h ../templates/locale.h ../core/config.h
misc.o: ../db/db.h ../db/dbbase.h ../db/dbconn.h ../db/dbtextstream.h
misc.o: ../core/textstream.h ../core/error.h ../db/dbitemquery.h
misc.o: ../db/dbitemcolumns.h ../core/user.h ../core/group.h
misc.o: ../core/dircontainer.h ../core/ugcontainer.h
misc.o: ../templates/htmltextstream.h ../core/cur.h ../core/system.h
misc.o: ../core/sessionmanager.h
mount.o: mount.h misc.h item.h
mountparser.o: mountparser.h mount.h item.h error.h dirs.h dircontainer.h
mountparser.o: ../db/db.h ../db/dbbase.h ../db/dbconn.h ../db/dbtextstream.h
mountparser.o: ../core/textstream.h misc.h ../core/error.h log.h textstream.h
mountparser.o: ../db/dbitemquery.h ../core/item.h ../db/dbitemcolumns.h
mountparser.o: ../core/user.h ../core/group.h ../core/dircontainer.h
mountparser.o: ../core/ugcontainer.h request.h requesttypes.h config.h
mountparser.o: confparser.h htmlfilter.h ../templates/htmltextstream.h
mountparser.o: ../notify/notify.h ../notify/notifypool.h
mountparser.o: ../templates/locale.h ../core/confparser.h ../templates/misc.h
mountparser.o: ../templates/localefilter.h ../templates/locale.h
mountparser.o: ../../ezc/src/ezc.h ../../ezc/src/utf8.h
mountparser.o: ../../ezc/src/generator.h ../../ezc/src/pattern.h
mountparser.o: ../../ezc/src/functions.h ../../ezc/src/funinfo.h
mountparser.o: ../../ezc/src/stringconv.h ../templates/htmltextstream.h
mountparser.o: ../notify/notifythread.h ../core/basethread.h synchro.h
mountparser.o: ../notify/templatesnotify.h ../core/config.h ../core/users.h
mountparser.o: user.h ugcontainer.h lastcontainer.h cur.h session.h
mountparser.o: plugindata.h rebus.h
mounts.o: mounts.h mount.h error.h dirs.h item.h dircontainer.h ../db/db.h
mounts.o: ../db/dbbase.h ../db/dbconn.h ../db/dbtextstream.h
mounts.o: ../core/textstream.h misc.h ../core/error.h log.h textstream.h
mounts.o: ../db/dbitemquery.h ../core/item.h ../db/dbitemcolumns.h
mounts.o: ../core/user.h ../core/group.h ../core/dircontainer.h
mounts.o: ../core/ugcontainer.h request.h requesttypes.h config.h
mounts.o: confparser.h htmlfilter.h ../templates/htmltextstream.h
mounts.o: ../notify/notify.h ../notify/notifypool.h ../templates/locale.h
mounts.o: ../core/confparser.h ../templates/misc.h
mounts.o: ../templates/localefilter.h ../templates/locale.h
mounts.o: ../../ezc/src/ezc.h ../../ezc/src/utf8.h ../../ezc/src/generator.h
mounts.o: ../../ezc/src/pattern.h ../../ezc/src/functions.h
mounts.o: ../../ezc/src/funinfo.h ../../ezc/src/stringconv.h
mounts.o: ../templates/htmltextstream.h ../notify/notifythread.h
mounts.o: ../core/basethread.h synchro.h ../notify/templatesnotify.h
mounts.o: ../core/config.h ../core/users.h user.h ugcontainer.h
mounts.o: lastcontainer.h cur.h session.h plugindata.h rebus.h mountparser.h
mounts.o: plugin.h pluginmsg.h system.h users.h groups.h group.h loadavg.h
mounts.o: thumb.h basethread.h sessionmanager.h sessioncontainer.h
mounts.o: ../functions/functions.h ../functions/functionbase.h
mounts.o: ../core/request.h ../core/system.h ../core/synchro.h
mounts.o: ../functions/functionparser.h ../core/cur.h ../functions/adduser.h
mounts.o: ../functions/cat.h ../functions/chmod.h ../functions/privchanger.h
mounts.o: ../functions/chown.h ../functions/ckeditor.h ../functions/cp.h
mounts.o: ../functions/default.h ../functions/download.h ../functions/emacs.h
mounts.o: ../functions/last.h ../functions/login.h ../functions/logout.h
mounts.o: ../functions/ln.h ../functions/ls.h ../functions/mkdir.h
mounts.o: ../functions/mv.h ../functions/node.h ../functions/priv.h
mounts.o: ../functions/reload.h ../functions/rm.h ../functions/run.h
mounts.o: ../functions/specialdefault.h ../functions/stat.h
mounts.o: ../functions/subject.h ../functions/template.h
mounts.o: ../functions/tinymce.h ../functions/uname.h ../functions/upload.h
mounts.o: ../functions/uptime.h ../functions/who.h ../functions/vim.h
mounts.o: ../core/htmlfilter.h ../templates/templates.h
mounts.o: ../templates/patterncacher.h ../templates/ckeditorgetparser.h
mounts.o: ../core/httpsimpleparser.h ../core/log.h
mounts.o: ../templates/indexpatterns.h ../core/sessionmanager.h
plugin.o: plugin.h pluginmsg.h log.h textstream.h plugindata.h config.h
plugin.o: confparser.h htmlfilter.h request.h requesttypes.h item.h error.h
plugin.o: ../templates/htmltextstream.h ../core/textstream.h misc.h system.h
plugin.o: dirs.h dircontainer.h ../db/db.h ../db/dbbase.h ../db/dbconn.h
plugin.o: ../db/dbtextstream.h ../core/error.h ../db/dbitemquery.h
plugin.o: ../core/item.h ../db/dbitemcolumns.h ../core/user.h ../core/group.h
plugin.o: ../core/dircontainer.h ../core/ugcontainer.h ../notify/notify.h
plugin.o: ../notify/notifypool.h ../templates/locale.h ../core/confparser.h
plugin.o: ../templates/misc.h ../templates/localefilter.h
plugin.o: ../templates/locale.h ../../ezc/src/ezc.h ../../ezc/src/utf8.h
plugin.o: ../../ezc/src/generator.h ../../ezc/src/pattern.h
plugin.o: ../../ezc/src/functions.h ../../ezc/src/funinfo.h
plugin.o: ../../ezc/src/stringconv.h ../templates/htmltextstream.h
plugin.o: ../notify/notifythread.h ../core/basethread.h synchro.h
plugin.o: ../notify/templatesnotify.h ../core/config.h ../core/users.h user.h
plugin.o: ugcontainer.h lastcontainer.h cur.h session.h rebus.h mounts.h
plugin.o: mount.h mountparser.h users.h groups.h group.h loadavg.h thumb.h
plugin.o: basethread.h sessionmanager.h sessioncontainer.h
plugin.o: ../functions/functions.h ../functions/functionbase.h
plugin.o: ../core/request.h ../core/system.h ../core/synchro.h
plugin.o: ../functions/functionparser.h ../core/cur.h ../functions/adduser.h
plugin.o: ../functions/cat.h ../functions/chmod.h ../functions/privchanger.h
plugin.o: ../functions/chown.h ../functions/ckeditor.h ../functions/cp.h
plugin.o: ../functions/default.h ../functions/download.h ../functions/emacs.h
plugin.o: ../functions/last.h ../functions/login.h ../functions/logout.h
plugin.o: ../functions/ln.h ../functions/ls.h ../functions/mkdir.h
plugin.o: ../functions/mv.h ../functions/node.h ../functions/priv.h
plugin.o: ../functions/reload.h ../functions/rm.h ../functions/run.h
plugin.o: ../functions/specialdefault.h ../functions/stat.h
plugin.o: ../functions/subject.h ../functions/template.h
plugin.o: ../functions/tinymce.h ../functions/uname.h ../functions/upload.h
plugin.o: ../functions/uptime.h ../functions/who.h ../functions/vim.h
plugin.o: ../core/htmlfilter.h ../templates/templates.h
plugin.o: ../templates/patterncacher.h ../templates/ckeditorgetparser.h
plugin.o: ../core/httpsimpleparser.h ../core/log.h
plugin.o: ../templates/indexpatterns.h ../core/sessionmanager.h
plugindata.o: plugindata.h plugin.h pluginmsg.h log.h textstream.h config.h
plugindata.o: confparser.h htmlfilter.h request.h requesttypes.h item.h
plugindata.o: error.h ../templates/htmltextstream.h ../core/textstream.h
plugindata.o: misc.h system.h dirs.h dircontainer.h ../db/db.h ../db/dbbase.h
plugindata.o: ../db/dbconn.h ../db/dbtextstream.h ../core/error.h
plugindata.o: ../db/dbitemquery.h ../core/item.h ../db/dbitemcolumns.h
plugindata.o: ../core/user.h ../core/group.h ../core/dircontainer.h
plugindata.o: ../core/ugcontainer.h ../notify/notify.h ../notify/notifypool.h
plugindata.o: ../templates/locale.h ../core/confparser.h ../templates/misc.h
plugindata.o: ../templates/localefilter.h ../templates/locale.h
plugindata.o: ../../ezc/src/ezc.h ../../ezc/src/utf8.h
plugindata.o: ../../ezc/src/generator.h ../../ezc/src/pattern.h
plugindata.o: ../../ezc/src/functions.h ../../ezc/src/funinfo.h
plugindata.o: ../../ezc/src/stringconv.h ../templates/htmltextstream.h
plugindata.o: ../notify/notifythread.h ../core/basethread.h synchro.h
plugindata.o: ../notify/templatesnotify.h ../core/config.h ../core/users.h
plugindata.o: user.h ugcontainer.h lastcontainer.h cur.h session.h rebus.h
plugindata.o: mounts.h mount.h mountparser.h users.h groups.h group.h
plugindata.o: loadavg.h thumb.h basethread.h sessionmanager.h
plugindata.o: sessioncontainer.h ../functions/functions.h
plugindata.o: ../functions/functionbase.h ../core/request.h ../core/system.h
plugindata.o: ../core/synchro.h ../functions/functionparser.h ../core/cur.h
plugindata.o: ../functions/adduser.h ../functions/cat.h ../functions/chmod.h
plugindata.o: ../functions/privchanger.h ../functions/chown.h
plugindata.o: ../functions/ckeditor.h ../functions/cp.h
plugindata.o: ../functions/default.h ../functions/download.h
plugindata.o: ../functions/emacs.h ../functions/last.h ../functions/login.h
plugindata.o: ../functions/logout.h ../functions/ln.h ../functions/ls.h
plugindata.o: ../functions/mkdir.h ../functions/mv.h ../functions/node.h
plugindata.o: ../functions/priv.h ../functions/reload.h ../functions/rm.h
plugindata.o: ../functions/run.h ../functions/specialdefault.h
plugindata.o: ../functions/stat.h ../functions/subject.h
plugindata.o: ../functions/template.h ../functions/tinymce.h
plugindata.o: ../functions/uname.h ../functions/upload.h
plugindata.o: ../functions/uptime.h ../functions/who.h ../functions/vim.h
plugindata.o: ../core/htmlfilter.h ../templates/templates.h
plugindata.o: ../templates/patterncacher.h ../templates/ckeditorgetparser.h
plugindata.o: ../core/httpsimpleparser.h ../core/log.h
plugindata.o: ../templates/indexpatterns.h ../core/sessionmanager.h
postmultiparser.o: postmultiparser.h error.h requesttypes.h config.h
postmultiparser.o: confparser.h htmlfilter.h log.h textstream.h
postmultiparser.o: ../../ezc/src/utf8.h misc.h item.h
rebus.o: log.h textstream.h rebus.h misc.h item.h cur.h request.h
rebus.o: requesttypes.h error.h config.h confparser.h htmlfilter.h
rebus.o: ../templates/htmltextstream.h ../core/textstream.h session.h user.h
rebus.o: plugindata.h
request.o: request.h requesttypes.h item.h error.h config.h confparser.h
request.o: htmlfilter.h textstream.h ../templates/htmltextstream.h
request.o: ../core/textstream.h misc.h log.h plugin.h pluginmsg.h
request.o: plugindata.h system.h dirs.h dircontainer.h ../db/db.h
request.o: ../db/dbbase.h ../db/dbconn.h ../db/dbtextstream.h ../core/error.h
request.o: ../db/dbitemquery.h ../core/item.h ../db/dbitemcolumns.h
request.o: ../core/user.h ../core/group.h ../core/dircontainer.h
request.o: ../core/ugcontainer.h ../notify/notify.h ../notify/notifypool.h
request.o: ../templates/locale.h ../core/confparser.h ../templates/misc.h
request.o: ../templates/localefilter.h ../templates/locale.h
request.o: ../../ezc/src/ezc.h ../../ezc/src/utf8.h ../../ezc/src/generator.h
request.o: ../../ezc/src/pattern.h ../../ezc/src/functions.h
request.o: ../../ezc/src/funinfo.h ../../ezc/src/stringconv.h
request.o: ../templates/htmltextstream.h ../notify/notifythread.h
request.o: ../core/basethread.h synchro.h ../notify/templatesnotify.h
request.o: ../core/config.h ../core/users.h user.h ugcontainer.h
request.o: lastcontainer.h cur.h session.h rebus.h mounts.h mount.h
request.o: mountparser.h users.h groups.h group.h loadavg.h thumb.h
request.o: basethread.h sessionmanager.h sessioncontainer.h
request.o: ../functions/functions.h ../functions/functionbase.h
request.o: ../core/request.h ../core/system.h ../core/synchro.h
request.o: ../functions/functionparser.h ../core/cur.h ../functions/adduser.h
request.o: ../functions/cat.h ../functions/chmod.h ../functions/privchanger.h
request.o: ../functions/chown.h ../functions/ckeditor.h ../functions/cp.h
request.o: ../functions/default.h ../functions/download.h
request.o: ../functions/emacs.h ../functions/last.h ../functions/login.h
request.o: ../functions/logout.h ../functions/ln.h ../functions/ls.h
request.o: ../functions/mkdir.h ../functions/mv.h ../functions/node.h
request.o: ../functions/priv.h ../functions/reload.h ../functions/rm.h
request.o: ../functions/run.h ../functions/specialdefault.h
request.o: ../functions/stat.h ../functions/subject.h ../functions/template.h
request.o: ../functions/tinymce.h ../functions/uname.h ../functions/upload.h
request.o: ../functions/uptime.h ../functions/who.h ../functions/vim.h
request.o: ../core/htmlfilter.h ../templates/templates.h
request.o: ../templates/patterncacher.h ../templates/ckeditorgetparser.h
request.o: ../core/httpsimpleparser.h ../core/log.h
request.o: ../templates/indexpatterns.h ../core/sessionmanager.h
session.o: session.h item.h error.h user.h plugindata.h rebus.h misc.h
sessioncontainer.o: sessioncontainer.h session.h item.h error.h user.h
sessioncontainer.o: plugindata.h rebus.h cur.h request.h requesttypes.h
sessioncontainer.o: config.h confparser.h htmlfilter.h textstream.h
sessioncontainer.o: ../templates/htmltextstream.h ../core/textstream.h misc.h
sessioncontainer.o: log.h
sessionmanager.o: sessionmanager.h sessioncontainer.h session.h item.h
sessionmanager.o: error.h user.h plugindata.h rebus.h cur.h request.h
sessionmanager.o: requesttypes.h config.h confparser.h htmlfilter.h
sessionmanager.o: textstream.h ../templates/htmltextstream.h
sessionmanager.o: ../core/textstream.h misc.h lastcontainer.h system.h dirs.h
sessionmanager.o: dircontainer.h ../db/db.h ../db/dbbase.h ../db/dbconn.h
sessionmanager.o: ../db/dbtextstream.h ../core/error.h log.h
sessionmanager.o: ../db/dbitemquery.h ../core/item.h ../db/dbitemcolumns.h
sessionmanager.o: ../core/user.h ../core/group.h ../core/dircontainer.h
sessionmanager.o: ../core/ugcontainer.h ../notify/notify.h
sessionmanager.o: ../notify/notifypool.h ../templates/locale.h
sessionmanager.o: ../core/confparser.h ../templates/misc.h
sessionmanager.o: ../templates/localefilter.h ../templates/locale.h
sessionmanager.o: ../../ezc/src/ezc.h ../../ezc/src/utf8.h
sessionmanager.o: ../../ezc/src/generator.h ../../ezc/src/pattern.h
sessionmanager.o: ../../ezc/src/functions.h ../../ezc/src/funinfo.h
sessionmanager.o: ../../ezc/src/stringconv.h ../templates/htmltextstream.h
sessionmanager.o: ../notify/notifythread.h ../core/basethread.h synchro.h
sessionmanager.o: ../notify/templatesnotify.h ../core/config.h
sessionmanager.o: ../core/users.h ugcontainer.h mounts.h mount.h
sessionmanager.o: mountparser.h users.h groups.h group.h loadavg.h thumb.h
sessionmanager.o: basethread.h sessionparser.h plugin.h pluginmsg.h
sessionmanager.o: ../functions/functions.h ../functions/functionbase.h
sessionmanager.o: ../core/request.h ../core/system.h ../core/synchro.h
sessionmanager.o: ../functions/functionparser.h ../core/cur.h
sessionmanager.o: ../functions/adduser.h ../functions/cat.h
sessionmanager.o: ../functions/chmod.h ../functions/privchanger.h
sessionmanager.o: ../functions/chown.h ../functions/ckeditor.h
sessionmanager.o: ../functions/cp.h ../functions/default.h
sessionmanager.o: ../functions/download.h ../functions/emacs.h
sessionmanager.o: ../functions/last.h ../functions/login.h
sessionmanager.o: ../functions/logout.h ../functions/ln.h ../functions/ls.h
sessionmanager.o: ../functions/mkdir.h ../functions/mv.h ../functions/node.h
sessionmanager.o: ../functions/priv.h ../functions/reload.h ../functions/rm.h
sessionmanager.o: ../functions/run.h ../functions/specialdefault.h
sessionmanager.o: ../functions/stat.h ../functions/subject.h
sessionmanager.o: ../functions/template.h ../functions/tinymce.h
sessionmanager.o: ../functions/uname.h ../functions/upload.h
sessionmanager.o: ../functions/uptime.h ../functions/who.h ../functions/vim.h
sessionmanager.o: ../core/htmlfilter.h ../templates/templates.h
sessionmanager.o: ../templates/patterncacher.h
sessionmanager.o: ../templates/ckeditorgetparser.h ../core/httpsimpleparser.h
sessionmanager.o: ../core/log.h ../templates/indexpatterns.h
sessionmanager.o: ../core/sessionmanager.h
sessionparser.o: sessionparser.h session.h item.h error.h user.h plugindata.h
sessionparser.o: rebus.h sessioncontainer.h cur.h request.h requesttypes.h
sessionparser.o: config.h confparser.h htmlfilter.h textstream.h
sessionparser.o: ../templates/htmltextstream.h ../core/textstream.h misc.h
sessionparser.o: users.h log.h
synchro.o: synchro.h
system.o: system.h dirs.h item.h dircontainer.h ../db/db.h ../db/dbbase.h
system.o: ../db/dbconn.h ../db/dbtextstream.h ../core/textstream.h misc.h
system.o: ../core/error.h log.h textstream.h ../db/dbitemquery.h
system.o: ../core/item.h ../db/dbitemcolumns.h ../core/user.h ../core/group.h
system.o: ../core/dircontainer.h ../core/ugcontainer.h request.h
system.o: requesttypes.h error.h config.h confparser.h htmlfilter.h
system.o: ../templates/htmltextstream.h ../notify/notify.h
system.o: ../notify/notifypool.h ../templates/locale.h ../core/confparser.h
system.o: ../templates/misc.h ../templates/localefilter.h
system.o: ../templates/locale.h ../../ezc/src/ezc.h ../../ezc/src/utf8.h
system.o: ../../ezc/src/generator.h ../../ezc/src/pattern.h
system.o: ../../ezc/src/functions.h ../../ezc/src/funinfo.h
system.o: ../../ezc/src/stringconv.h ../templates/htmltextstream.h
system.o: ../notify/notifythread.h ../core/basethread.h synchro.h
system.o: ../notify/templatesnotify.h ../core/config.h ../core/users.h user.h
system.o: ugcontainer.h lastcontainer.h cur.h session.h plugindata.h rebus.h
system.o: mounts.h mount.h mountparser.h users.h groups.h group.h loadavg.h
system.o: thumb.h basethread.h ../templates/templates.h
system.o: ../templates/patterncacher.h ../templates/ckeditorgetparser.h
system.o: ../core/httpsimpleparser.h ../core/log.h
system.o: ../templates/indexpatterns.h ../core/cur.h ../core/system.h
system.o: ../core/sessionmanager.h ../functions/functionbase.h
system.o: ../core/request.h ../core/synchro.h
textstream.o: textstream.h misc.h item.h
thumb.o: thumb.h basethread.h textstream.h ../db/db.h ../db/dbbase.h
thumb.o: ../db/dbconn.h ../db/dbtextstream.h ../core/textstream.h misc.h
thumb.o: item.h ../core/error.h log.h ../db/dbitemquery.h ../core/item.h
thumb.o: ../db/dbitemcolumns.h ../core/user.h ../core/group.h
thumb.o: ../core/dircontainer.h ../core/ugcontainer.h ../core/config.h
thumb.o: ../../ezc/src/utf8.h system.h dirs.h dircontainer.h request.h
thumb.o: requesttypes.h error.h config.h confparser.h htmlfilter.h
thumb.o: ../templates/htmltextstream.h ../notify/notify.h
thumb.o: ../notify/notifypool.h ../templates/locale.h ../core/confparser.h
thumb.o: ../templates/misc.h ../templates/localefilter.h
thumb.o: ../templates/locale.h ../../ezc/src/ezc.h ../../ezc/src/generator.h
thumb.o: ../../ezc/src/pattern.h ../../ezc/src/functions.h
thumb.o: ../../ezc/src/funinfo.h ../../ezc/src/stringconv.h
thumb.o: ../templates/htmltextstream.h ../notify/notifythread.h
thumb.o: ../core/basethread.h synchro.h ../notify/templatesnotify.h
thumb.o: ../core/users.h user.h ugcontainer.h lastcontainer.h cur.h session.h
thumb.o: plugindata.h rebus.h mounts.h mount.h mountparser.h users.h groups.h
thumb.o: group.h loadavg.h
users.o: users.h

1
core/Makefile.o.dep Executable file
View File

@@ -0,0 +1 @@
o = acceptbaseparser.o app.o basethread.o bbcodeparser.o compress.o config.o confparser.o dircontainer.o dirs.o groups.o htmlfilter.o httpsimpleparser.o item.o lastcontainer.o loadavg.o log.o misc.o mount.o mountparser.o mounts.o plugin.o plugindata.o postmultiparser.o rebus.o request.o session.o sessioncontainer.o sessionmanager.o sessionparser.o synchro.o system.o textstream.o thumb.o users.o

113
core/acceptbaseparser.cpp Executable file
View File

@@ -0,0 +1,113 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "acceptbaseparser.h"
bool AcceptBaseParser::IsWhite(int c)
{
if( c==' ' || c=='\t' )
return true;
return false;
}
void AcceptBaseParser::SkipWhite()
{
while( IsWhite(*text) )
++text;
}
void AcceptBaseParser::RemoveWhiteFromEnd(std::string & str)
{
if( str.empty() )
return;
size_t i = str.size() - 1;
for( ; i!=0 && IsWhite(str[i]) ; --i);
if( !IsWhite(str[i]) )
++i;
if( i < str.size() )
str.erase(i); // erasing until the end of the string
}
void AcceptBaseParser::ReadParameter()
{
param.clear();
SkipWhite();
while( *text!=0 && *text!=',' && *text!=';' )
{
param += *text;
++text;
}
RemoveWhiteFromEnd(param);
}
void AcceptBaseParser::ReadQ()
{
q = 1.0;
SkipWhite();
if( *text != ';' )
return;
++text; // skipping a semicolon
while( *text!=0 && *text!=',' && *text!='=' )
// skipping until ',' or '='
++text;
if( *text==0 || *text==',' )
return;
++text; // skipping '='
SkipWhite();
q = strtod(text, (char**)&text);
}
void AcceptBaseParser::SkipParam()
{
SkipWhite();
if( *text == ',' )
++text;
}
void AcceptBaseParser::Parse(const char * str)
{
text = str;
Init();
while( *text != 0 )
{
ReadParameter();
ReadQ();
SkipParam();
Param(param, q);
}
}

47
core/acceptbaseparser.h Executable file
View File

@@ -0,0 +1,47 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_acceptbaseparser
#define headerfile_winix_core_acceptbaseparser
#include <string>
// sample (you must create your own class derived from this one):
// object.Parse(" text/html ; , ; q = 45, application / xhtml+xml ; q = 0.4 , application/xml ; q = 0.9 , */* ; q = 0.8 ");
class AcceptBaseParser
{
public:
void Parse(const char * str);
private:
virtual void Init() {} ;
virtual void Param(const std::string & param, double q) = 0;
bool IsWhite(int c);
void SkipWhite();
void RemoveWhiteFromEnd(std::string & str);
void ReadParameter();
void ReadQ();
void SkipParam();
const char * text;
std::string param;
double q;
};
#endif

49
core/acceptencodingparser.h Executable file
View File

@@ -0,0 +1,49 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_acceptencodingparser
#define headerfile_winix_core_acceptencodingparser
#include "acceptbaseparser.h"
#include "log.h"
class AcceptEncodingParser : public AcceptBaseParser
{
public:
bool AcceptDeflate()
{
return accept_deflate;
}
private:
void Init()
{
accept_deflate = false;
}
void Param(const std::string & param, double q)
{
if( param=="deflate" && q!=0 )
{
accept_deflate = true;
log << log3 << "AEP: accept deflate" << logend;
}
}
bool accept_deflate;
};
#endif

1073
core/app.cpp Executable file

File diff suppressed because it is too large Load Diff

182
core/app.h Executable file
View File

@@ -0,0 +1,182 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_app
#define headerfile_winix_core_app
#include <iostream>
#include <ctime>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include <fcgiapp.h>
#include "config.h"
#include "system.h"
#include "mounts.h"
#include "request.h"
#include "synchro.h"
#include "sessionmanager.h"
#include "db/db.h"
#include "functions/functions.h"
#include "templates/templates.h"
#include "compress.h"
#include "htmlfilter.h"
#include "getparser.h"
#include "postparser.h"
#include "cookieparser.h"
#include "postmultiparser.h"
#include "acceptencodingparser.h"
class App
{
public:
App();
bool InitFCGI();
bool DropPrivileges();
bool Init();
void Start();
void Close();
void LogUserGroups();
bool Demonize();
void SetStopSignal();
bool WasStopSignal();
bool Lock();
void Unlock();
void StartThreads();
void WaitForThreads();
// configuration read from a config file
Config config;
// pointers to the current request and a session
Cur cur;
// temporary one request object
// current request
Request req;
// users sessions
SessionManager session_manager;
// database
Db db;
DbConn db_conn;
/*
model
*/
// file system
System system;
// false at the beginning
// !! moze to do loggera dac?
bool stdout_is_closed;
/*
controllers
(note that the whole app object is actually a controller too)
*/
// functions (ls, cat, emacs, ...)
Functions functions;
/*
view
*/
Templates templates;
private:
enum Header
{
h_200,
h_404,
h_403
};
GetParser get_parser;
PostParser post_parser;
PostMultiParser post_multi_parser;
CookieParser cookie_parser;
AcceptEncodingParser accept_encoding_parser;
Compress compress;
HTMLFilter html_filter;
std::wstring clean_html, html_with_debug;
FCGX_Request fcgi_request;
int fcgi_socket;
Synchro synchro;
pthread_t signal_thread;
std::string url_to_fetch_on_exit;
void ProcessRequestThrow();
void ProcessRequest();
bool BaseUrlRedirect();
void MakePage();
void Make();
void SaveSessionsIfNeeded(); // !! wywalic do menagera sesji??
void LogAccess();
void ReadRequest();
void SendAnswer();
void SetEnv(const char * & env, const char * name);
void ReadEnvVariables();
void ReadGetPostVars();
void CheckIE();
void CheckKonqueror();
void CheckRequestMethod();
void CheckFCGIRole();
void SetHtmlFilterConf();
void PrepareSessionCookie();
void AddDebugInfo(std::wstring & out);
void FilterCompressSend(bool compressing, const std::wstring & source_ref);
void SendHeaders(bool compressing, Header header);
bool IsCompressionAllowed(const std::wstring & source);
bool CanSendContent(Header header);
void LogUser(const char * msg, uid_t id);
void LogGroup(const char * msg, gid_t id, bool put_logend = true);
void LogUsers();
void LogEffectiveGroups(std::vector<gid_t> & tab);
void LogGroups();
bool DropPrivileges(const std::string & user, uid_t uid, gid_t gid, bool additional_groups);
static void * SpecialThreadForSignals(void*);
void FetchPageOnExit();
void CreateStaticTree();
// !! dodac do session managera?
time_t last_sessions_save;
};
#endif

232
core/basethread.cpp Executable file
View File

@@ -0,0 +1,232 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#include <errno.h>
#include "basethread.h"
#include "log.h"
BaseThread::BaseThread() : thread_signal(PTHREAD_COND_INITIALIZER)
{
synchro = 0;
thread_id = 0;
work_mode = 0;
wake_up_was_called = false;
}
void BaseThread::SetSynchro(Synchro * psynchro)
{
synchro = psynchro;
}
void BaseThread::Mode(int mode)
{
work_mode = mode;
}
bool BaseThread::Lock()
{
return synchro->Lock();
}
void BaseThread::Unlock()
{
synchro->Unlock();
}
bool BaseThread::IsExitSignal()
{
bool res = true;
if( Lock() )
{
res = synchro->was_stop_signal;
Unlock();
}
return res;
}
bool BaseThread::BaseInit()
{
bool init_status = false;
if( Lock() )
{
init_status = Init(); // your virtual method
Unlock();
}
return init_status;
}
void BaseThread::BaseUninit()
{
if( Lock() )
{
Uninit(); // your virtual method
Unlock();
}
}
bool BaseThread::BaseSignalReceived()
{
bool make_do = false;
wake_up_was_called = false;
try
{
make_do = SignalReceived(); // your short-time virtual method (objects are locked)
}
catch(...)
{
}
return make_do;
}
// this is called only if your SignalReceived() returned true
void BaseThread::BaseDo()
{
try
{
Do(); // your long-time virtual method (objects are *not* locked)
}
catch(...)
{
}
}
// use it with Lock and Unlock
bool BaseThread::WaitForSignal()
{
if( synchro->was_stop_signal || wake_up_was_called )
return true;
return pthread_cond_wait(&thread_signal, &synchro->mutex) == 0;
}
// you should use this method with: synchro->Lock() and Unlock()
void BaseThread::WakeUpThread()
{
wake_up_was_called = true;
pthread_cond_signal(&thread_signal);
}
// use it with Lock and Unlock
// it breaks only if there was a stop signal or the time has expired
bool BaseThread::WaitForSignalSleep(time_t second)
{
timespec t;
int res;
if( synchro->was_stop_signal )
return true;
t.tv_sec = time(0) + second;
t.tv_nsec = 0;
do
{
res = pthread_cond_timedwait(&thread_signal, &synchro->mutex, &t);
}
while( res == 0 && !synchro->was_stop_signal );
// above condition means there was a signal
// but it was not a stop signal so we should still wait
return res == 0 || res == ETIMEDOUT;
}
void BaseThread::WaitForThread()
{
pthread_join(thread_id, 0);
}
void BaseThread::SignalLoop()
{
bool make_do;
do
{
if( Lock() )
{
make_do = false;
if( WaitForSignal() ) // automatically unlock, wait and lock again when signal comes
if( !synchro->was_stop_signal )
make_do = BaseSignalReceived(); // your short-time virtual method will be called (objects locked)
Unlock(); // unlocking from WaitForSignal()
if( make_do )
BaseDo(); // your long-time virtual method will be called (objects *not* locked)
}
}
while( !IsExitSignal() );
}
void * BaseThread::StartRoutine(void * this_object)
{
BaseThread * base = reinterpret_cast<BaseThread*>(this_object);
if( base->synchro )
{
if( base->BaseInit() )
{
if( base->work_mode == 0 )
base->SignalLoop();
else
base->Work();
base->BaseUninit();
}
}
pthread_exit(0);
return 0;
}
bool BaseThread::StartThread()
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int res = pthread_create(&thread_id, &attr, StartRoutine, this);
pthread_attr_destroy(&attr);
return res == 0;
}

121
core/basethread.h Executable file
View File

@@ -0,0 +1,121 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_basethread
#define headerfile_winix_core_basethread
#include <pthread.h>
#include "synchro.h"
class BaseThread
{
public:
BaseThread();
// synchro object (must be set)
void SetSynchro(Synchro * psynchro);
// work mode
// we have two modes:
// 0 - there is a loop with SignalReceived() and Do()
// if SignalReceived() returns true then Do() is called
// 1 - only Work() method is called
// the thread exits after Work() has finished
// default: 0
void Mode(int mode);
// starting the second thread
bool StartThread();
// wake up the second thread
// (if it waits for the signal)
// you should use it with: synchro->Lock() and Unlock()
// if the thread doesn't wait on a signal then nothing is done
void WakeUpThread();
// waiting until the thread exits
// you should call WakeUpThread() before
void WaitForThread();
// virtual methods which should/can be inherited by your class
// the methods will be called from the other thread
// initialize the thread
// (global objects are locked)
// if it returns false then the thread immediately exits
// default: true
virtual bool Init() { return true; }
// uninitialize the thread
// this is called before the thread is prepare to detach
// (global objects are locked)
// it's called only if Init() returned true
virtual void Uninit() {}
protected:
// signal came (work mode = 0 - default)
// signal comes when an other thread calls WakeUpThread() method
// check specific job and return true to call Do() next
// (global objects are locked -- copy some global objects to local variables)
virtual bool SignalReceived() { return false; };
// if SignalReceived() returned true then this method is called
// global objects are *not* locked -- use only your local variables
// if you have to do something on global objects use synchro->Lock() and synchro->Unlock()
virtual void Do() {}
// this method is called after Init() when Mode(1) is used
// this is for long-time job
// this method is called only once
// global objects are *not* locked
virtual void Work() {}
protected:
Synchro * synchro;
pthread_t thread_id; // thread id - set by StartThread()
pthread_cond_t thread_signal;
int work_mode;
bool wake_up_was_called;
void SignalLoop();
static void * StartRoutine(void *);
bool BaseInit();
void BaseUninit();
bool BaseSignalReceived();
void BaseDo();
bool WaitForSignal();
bool WaitForSignalSleep(time_t second);
bool Lock();
void Unlock();
// if the work done by Do() is long time consuming you should periodically check
// wheter there was a signal for exiting, and if it was just simply return from Do()
// (it's checking with locking and unlocking)
bool IsExitSignal();
};
#endif

577
core/bbcodeparser.cpp Executable file
View File

@@ -0,0 +1,577 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "bbcodeparser.h"
bool BBCODEParser::Equal(const wchar_t * str1, const wchar_t * str2)
{
while( *str1 == *str2 && *str1 != 0 )
{
str1 += 1;
str2 += 1;
}
return *str1 == *str2;
}
bool BBCODEParser::IsValidCharForName(int c)
{
if( (c>='a' && c<='z') ||
(c>='A' && c<='Z') ||
c=='*' || c=='_')
return true;
return false;
}
bool BBCODEParser::IsOpeningTagMark()
{
return (*pchar == '[');
}
// there are no commentaries in bbcode
bool BBCODEParser::IsOpeningCommentaryTagMark()
{
return false;
}
bool BBCODEParser::SkipCommentaryTagIfExists()
{
return false;
}
bool BBCODEParser::IsClosingTagMark()
{
return (*pchar == ']');
}
bool BBCODEParser::IsClosingXmlSimpleTagMark()
{
return false;
}
// one enter will generate one <br>
// two enters or more will generate only two br (<br><br>)
void BBCODEParser::PutNormalText(const wchar_t * str, const wchar_t * end)
{
int br_len;
if( *pchar == 0 )
{
// trimming last white characters at end of the user text
while( str<end && (IsWhite(*(end-1)) || *(end-1)==10) )
--end;
}
while( str < end )
{
if( *str == 10 )
{
++str;
br_len = 1;
// skipping white characters without a new line character
while( str < end && IsWhite(*str) )
++str;
if( str < end && *str == 10 )
{
br_len = 2;
// skipping white characters with new line characters
while( str < end && (IsWhite(*str) || *str==10) )
++str;
}
if( !has_open_ol_tag && !has_open_ul_tag && !has_open_li_tag )
{
for(int i=0 ; i < br_len ; ++i)
(*out_string) += L"<br>\n";
}
}
else
{
PrintEscape(*str);
++str;
}
}
}
void BBCODEParser::PutNormalTextTrim(const wchar_t * str, const wchar_t * end)
{
// we don't use trimming in bbcode parser
PutNormalText(str, end);
}
void BBCODEParser::ReadNormalTextSkipWhite(const wchar_t * & start, const wchar_t * & last_non_white)
{
}
void BBCODEParser::CheckExceptions()
{
if( stack_len >= 2 )
{
if( pstack[stack_len-1].type == Item::opening &&
pstack[stack_len-2].type == Item::opening &&
IsNameEqual(L"*", pstack[stack_len-1].name) &&
IsNameEqual(L"*", pstack[stack_len-2].name) )
{
// removing the last [*] from the stack
// </li> was put automatically
PopStack();
}
}
}
/*
bbcode format:
[bbcodetag=value]some text[/bbcodetag]
the value can be quoted, e.g.
[bbcodetag="value"]some text[/bbcodetag], or
[bbcodetag='value']some text[/bbcodetag]
the third string below (in tags table) is 'html_argument' from Tags,
it can contain a special character % followed by a string which means:
%1 - "value" escaped as for html
%2 - "some text" escaped as for html
%u1 - "value" trimmed and escaped as for url-es
%u2 - "some text" trimmed and escaped as for url-es
%% - one %
if you are using %2 or %u2 then "some text" is not treated as bbcode, e.g.
[bbcodetag=value]some [b]text[/b][/bbcodetag] will produce:
<htmltag arg="value">some [b]text[/b]</htmltag> (the inner tags [b][/b] were not parsed)
also when using %2 or %u2 the closing bbcode tag is skipped
(if you want this tag then you can put it in 'html_argument')
and when using u (%u1 or %u2) the argument is trimmed from whitespaces and new lines
at the beginning and at the end
(because otherwise a space would be changed to %20 and this were probably not what you really wanted)
*/
const BBCODEParser::Tags * BBCODEParser::FindTag(const wchar_t * tag)
{
static Tags tags[] = {
{L"*", L"li", L">", false},
{L"b", L"em", L">", true},
{L"i", L"span", L" class=\"bbitalic\">", true},
{L"u", L"span", L" class=\"bbunderline\">", true},
{L"s", L"span", L" class=\"bbstrike\">", true},
{L"code", L"code", L" class=\"bbcode\">", false},
{L"list", L"ul", L" class=\"bblist\">", false},
{L"color", L"span", L" class=\"bbcol%1\">", true},
{L"url", L"a", L" href=\"%u1\">", true},
{L"img", L"img", L" alt=\"%1\" src=\"%u2\">", true},
{L"quote", L"div", L" class=\"bbquote\">\n<span class=\"bbquotewho\">%1</span><br>\n", false},
};
size_t i;
size_t len = sizeof(tags) / sizeof(Tags);
for(i=0 ; i<len ; ++i)
{
if( Equal(tag, tags[i].bbcode) )
return &tags[i];
}
return 0;
}
void BBCODEParser::PrintArgumentCheckQuotes(const wchar_t * & start, const wchar_t * & end)
{
// skipping white characters from the argument
while( start<end && IsWhite(*start) )
++start;
// skipping first '=' character if exists
if( start<end && *start == '=' )
++start;
// skipping white characters from the argument
// at the beginning
while( start<end && IsWhite(*start) )
++start;
// and at the end
while( start<end && IsWhite(*(end-1)) )
--end;
if( start<end && (*start=='\'' || *start=='\"') )
{
++start;
if( start<end && *(start-1) == *(end-1) )
--end;
// skipping white characters after a first quote char [url = " ww...."]
while( start<end && IsWhite(*start) )
++start;
}
}
void BBCODEParser::PrintEncode(int c)
{
if( c == '&' )
{
(*out_string) += L"&amp;";
}
else
if( (c>='a' && c<='z') ||
(c>='A' && c<='Z') ||
(c>='0' && c<='9') ||
(c=='_' || c=='?' || c=='.' || c==',' || c=='/' || c=='-' ||
c=='+' || c=='*' || c=='(' || c==')' || c=='=' || c==':')
)
{
(*out_string) += c;
}
else
{
wchar_t buffer[20];
swprintf(buffer, 20, L"%02X", c);
(*out_string) += '%';
(*out_string) += buffer;
}
}
void BBCODEParser::PrintEscape(int c, bool change_quote)
{
if( c == '<' )
{
(*out_string) += L"&lt;";
}
else
if( c == '>' )
{
(*out_string) += L"&gt;";
}
else
if( c == '&' )
{
(*out_string) += L"&amp;";
}
else
if( c == '\"' && change_quote )
{
(*out_string) += L"&quot;";
}
else
{
(*out_string) += c;
}
}
void BBCODEParser::PrintArgumentEncode(const wchar_t * start, const wchar_t * end)
{
PrintArgumentCheckQuotes(start, end);
TrimWhiteWithNewLines(start, end);
for( ; start<end ; ++start )
PrintEncode(*start);
}
void BBCODEParser::PrintArgumentEscape(const wchar_t * start, const wchar_t * end)
{
PrintArgumentCheckQuotes(start, end);
for( ; start<end ; ++start )
PrintEscape(*start, true); // quotes are escaped as well here
}
void BBCODEParser::CheckOpeningTag(const Tags * tag, const wchar_t * tag_name, bool & condition)
{
if( Equal(tag->html_tag, tag_name) )
{
if( condition )
{
PutClosingTag(tag);
(*out_string) += '\n';
}
condition = true;
}
}
void BBCODEParser::CheckOpeningTag(const Tags * tag)
{
bool has_list_tag = has_open_ul_tag || has_open_ol_tag;
CheckOpeningTag(tag, L"li", has_open_li_tag);
CheckOpeningTag(tag, L"ul", has_open_ul_tag);
CheckOpeningTag(tag, L"ol", has_open_ol_tag);
if( has_open_li_tag && !has_list_tag )
{
(*out_string) += L"<ul>\n";
has_open_ul_tag = true;
}
}
void BBCODEParser::PrintEscape(const wchar_t * start, const wchar_t * end, bool change_quote)
{
for( ; start < end ; ++start)
PrintEscape(*start, change_quote);
}
void BBCODEParser::PrintEncode(const wchar_t * start, const wchar_t * end)
{
for( ; start < end ; ++start)
PrintEncode(*start);
}
void BBCODEParser::PutOpeningTagFromEzc(const wchar_t * start, const wchar_t * end)
{
// this can be a tag from Ezc templates system
(*out_string) += '[';
(*out_string) += LastItem().name;
if( start != end )
{
(*out_string) += ' ';
PrintEscape(start, end);
}
(*out_string) += ']';
}
void BBCODEParser::PutHtmlArgument1(const wchar_t * arg_start, const wchar_t * arg_end, bool has_u)
{
if( has_u )
PrintArgumentEncode(arg_start, arg_end);
else
PrintArgumentEscape(arg_start, arg_end);
}
void BBCODEParser::TrimWhiteWithNewLines(const wchar_t * & start, const wchar_t * & end)
{
while( start < end && (IsWhite(*start) || *start==10) )
++start;
while( start < end && (IsWhite(*(end-1)) || *(end-1)==10) )
--end;
}
void BBCODEParser::PutHtmlArgument2(const Tags * tag, bool has_u)
{
const wchar_t * start = pchar;
const wchar_t * end = pchar;
bool first_tag_removed = false;
while( *pchar != 0 )
{
if( IsOpeningTagMark() )
{
if( IsClosingTagForLastItem() )
{
// the last tag is skipped when using patterns with %2 or %u2
PopStack(); // removing opening tag from the stack
first_tag_removed = true;
break;
}
}
else
{
pchar += 1;
end = pchar;
}
}
if( !first_tag_removed )
PopStack(); // user has forgotten to close the tag
if( has_u )
{
TrimWhiteWithNewLines(start, end);
PrintEncode(start, end);
}
else
{
PrintEscape(start, end);
}
}
void BBCODEParser::PutHtmlArgument(const Tags * tag, const wchar_t * arg_start, const wchar_t * arg_end)
{
const wchar_t * pattern = tag->html_argument;
bool has_u;
while( *pattern )
{
if( *pattern == '%' )
{
++pattern;
has_u = false;
if( *pattern == 'u' )
{
++pattern;
has_u = true;
}
if( *pattern == '1' )
{
++pattern;
PutHtmlArgument1(arg_start, arg_end, has_u);
}
else
if( *pattern == '2' )
{
++pattern;
PutHtmlArgument2(tag, has_u);
}
else
if( *pattern == '%' )
{
(*out_string) += '%';
++pattern;
}
// else unrecognized, will be printed next time as a normal character
}
else
{
(*out_string) += *pattern;
++pattern;
}
}
}
void BBCODEParser::PutOpeningTagFromBBCode(const Tags * tag, const wchar_t * start, const wchar_t * end)
{
CheckOpeningTag(tag);
PutOpeningTagMark();
(*out_string) += tag->html_tag;
PutHtmlArgument(tag, start, end);
if( !tag->inline_tag )
{
(*out_string) += L"\n";
SkipWhiteLines();
}
}
void BBCODEParser::PutOpeningTag(const wchar_t * start, const wchar_t * end)
{
const Tags * tag = FindTag(LastItem().name);
if( !tag )
{
PutOpeningTagFromEzc(start, end);
}
else
{
PutOpeningTagFromBBCode(tag, start, end);
}
}
void BBCODEParser::PutClosingTag(const Tags * tag)
{
if( !tag )
return; // skipping the tag
PutOpeningTagMark();
(*out_string) += '/';
(*out_string) += tag->html_tag;
PutClosingTagMark();
if( !tag->inline_tag )
{
(*out_string) += L"\n";
SkipWhiteLines();
}
if( Equal(tag->html_tag, L"li") )
has_open_li_tag = false;
if( Equal(tag->html_tag, L"ol") )
has_open_ol_tag = false;
if( Equal(tag->html_tag, L"ul") )
has_open_ul_tag = false;
}
void BBCODEParser::PutClosingTag(const wchar_t * tag_name)
{
const Tags * tag = FindTag(tag_name);
PutClosingTag(tag);
}
void BBCODEParser::Init()
{
has_open_li_tag = false;
has_open_ol_tag = false;
has_open_ul_tag = false;
SkipWhiteLines();
}
void BBCODEParser::Deinit()
{
if( has_open_li_tag )
(*out_string) += L"</li>\n";
if( has_open_ol_tag )
(*out_string) += L"</ol>\n";
if( has_open_ul_tag )
(*out_string) += L"</ul>\n";
}

97
core/bbcodeparser.h Executable file
View File

@@ -0,0 +1,97 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_bbcodeparser
#define headerfile_winix_core_bbcodeparser
#include "htmlfilter.h"
class BBCODEParser : public HTMLFilter
{
//using HTMLFilter::pchar;
struct Tags
{
/*
const wchar_t * bbcode;
const wchar_t * html_tag;
const wchar_t * html_arg_prefix;
const wchar_t * html_arg_postfix;
const wchar_t * additional_html_tag_prefix;
const wchar_t * additional_html_tag_postfix;
bool inline_tag;
*/
const wchar_t * bbcode;
const wchar_t * html_tag;
const wchar_t * html_argument; // with closing '>'
bool inline_tag;
};
bool Equal(const wchar_t * str1, const wchar_t * str2);
virtual bool IsValidCharForName(int c);
virtual bool IsOpeningTagMark();
virtual bool IsOpeningCommentaryTagMark();
virtual bool SkipCommentaryTagIfExists();
virtual bool IsClosingTagMark();
virtual bool IsClosingXmlSimpleTagMark();
void PutHtmlArgument1(const wchar_t * arg_start, const wchar_t * arg_end, bool has_u);
void PutHtmlArgument2(const Tags * tag, bool has_u);
void PutHtmlArgument(const Tags * tag, const wchar_t * arg_start, const wchar_t * arg_end);
void PutOpeningTagFromEzc(const wchar_t * start, const wchar_t * end);
void PutOpeningTagFromBBCode(const Tags * tag, const wchar_t * start, const wchar_t * end);
virtual void PutOpeningTag(const wchar_t * start, const wchar_t * end);
virtual void PutClosingTag(const wchar_t * tag);
const Tags * FindTag(const wchar_t * tag);
void PrintArgumentCheckQuotes(const wchar_t * & start, const wchar_t * & end);
void PrintEscape(int c, bool change_quote = false);
void PrintEncode(int c);
void PrintEscape(const wchar_t * start, const wchar_t * end, bool change_quote = false);
void PrintEncode(const wchar_t * start, const wchar_t * end);
void PrintArgumentEncode(const wchar_t * start, const wchar_t * end);
void PrintArgumentEscape(const wchar_t * start, const wchar_t * end);
virtual void ReadNormalTextSkipWhite(const wchar_t * & start, const wchar_t * & last_non_white);
virtual void PutNormalText(const wchar_t * str, const wchar_t * end);
virtual void PutNormalTextTrim(const wchar_t * str, const wchar_t * end);
virtual void CheckExceptions();
virtual void Init();
virtual void Deinit();
void PutClosingTag(const Tags * tag);
void CheckOpeningTag(const Tags * tag, const wchar_t * tag_name, bool & condition);
void CheckOpeningTag(const Tags * tag);
void TrimWhiteWithNewLines(const wchar_t * & start, const wchar_t * & end);
bool has_open_ol_tag; // has open html <ol> tag
bool has_open_ul_tag; // has open html <ul> tag
bool has_open_li_tag; // has open html <li> tag
};
#endif

175
core/compress.cpp Executable file
View File

@@ -0,0 +1,175 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "compress.h"
#include "log.h"
Compress::Compress()
{
buffer = 0;
buffer_max_len = 65536; // 64KB
ready_for_compress = false;
}
Compress::~Compress()
{
if( buffer )
delete [] buffer;
}
bool Compress::AllocateMemory()
{
if( buffer )
delete [] buffer;
try
{
buffer = new char[buffer_max_len];
}
catch(const std::bad_alloc &)
{
log << log1 << "Compress: can't allocate memory" << logend;
buffer = 0;
return false;
}
return true;
}
/*
return:
0 - ok;
1 - can't allocate memory
100 - unknown
*/
int Compress::Init(int compress_level)
{
if( buffer == 0 )
if( !AllocateMemory() )
return 1;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
int ret = deflateInit(&strm, compress_level);
if( ret != Z_OK )
log << log1 << "Compress: problem with deflateInit()" << logend;
if( ret == Z_MEM_ERROR )
return 1;
if( ret != Z_OK )
return 100;
ready_for_compress = true;
return 0;
}
int Compress::MakeCompress(const char * source, size_t source_len, FCGX_Stream * out_stream)
{
int ret, flush;
size_t have;
do
{
strm.avail_in = (source_len > buffer_max_len) ? buffer_max_len : source_len;
source_len -= strm.avail_in;
flush = (source_len == 0) ? Z_FINISH : Z_NO_FLUSH;
strm.next_in = (Bytef*)source;
source += strm.avail_in;
do
{
strm.avail_out = buffer_max_len;
strm.next_out = (Bytef*)buffer;
ret = deflate(&strm, flush);
if( ret == Z_STREAM_ERROR || ret == Z_BUF_ERROR )
{
log << log1 << "Compress: problem with deflate()" << logend;
return 2;
}
have = buffer_max_len - strm.avail_out;
last_out_size += have;
FCGX_PutStr(buffer, have, out_stream);
}
while( strm.avail_out == 0 );
if( strm.avail_in != 0 )
{
log << log1 << "Compress: problem with deflate() - not all input is used" << logend;
return 2;
}
}
while( flush != Z_FINISH );
if( ret != Z_STREAM_END )
{
log << log1 << "Compress: problem with deflate() - stream not complete" << logend;
return 2;
}
return 0;
}
/*
return:
0 - ok;
1 - can't allocate memory
2 - error during compressing
3 - not inited (use Init() first)
100 - unknown
*/
int Compress::CompressAndPut(const char * source, size_t source_len, FCGX_Stream * out_stream, int level)
{
int ret;
last_out_size = 0;
if( !ready_for_compress )
{
log << log1 << "Compress: not ready yet" << logend;
return 3;
}
if( source_len == 0 )
return 0;
ret = MakeCompress(source, source_len, out_stream);
if( deflateReset(&strm) != Z_OK )
log << log1 << "Compress: problem with deflateReset()" << logend;
double ratio = 100.0 - (double(last_out_size) / double(source_len) * 100.0);
char buffer[30];
sprintf(buffer, "%.1f", ratio);
log << log2 << "Compress: original size: " << source_len << ", compress size: " << (int)last_out_size << ", ratio: " << buffer << "%" << logend;
return ret;
}

43
core/compress.h Executable file
View File

@@ -0,0 +1,43 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_compress
#define headerfile_winix_core_compress
#include <cstring>
#include <fcgiapp.h>
#include <zlib.h>
class Compress
{
public:
Compress();
~Compress();
int Init(int compress_level = 6);
int CompressAndPut(const char * source, size_t source_len, FCGX_Stream * out_stream, int level = 6);
size_t last_out_size;
private:
bool AllocateMemory();
int MakeCompress(const char * source, size_t source_len, FCGX_Stream * out_stream);
size_t buffer_max_len;
char * buffer;
z_stream strm;
bool ready_for_compress;
};
#endif

349
core/config.cpp Executable file
View File

@@ -0,0 +1,349 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "config.h"
#include "log.h"
#include "plugin.h"
#include "misc.h"
Config::Config()
{
errors_to_stdout = true;
}
//!! czy tu w ogole mozemy uzywac log << ?
//!! przeciez jeszcze nie zostal przetworzony plik konfiguracyjny
void Config::ShowError()
{
switch( parser.status )
{
case ConfParser::ok:
log << log2 << "Config: syntax ok" << logend;
break;
case ConfParser::cant_open_file:
if( errors_to_stdout )
std::cout << "Config: cant open a config file: " << config_file << std::endl;
log << log1 << "Config: cant open a config file: " << config_file << logend;
break;
case ConfParser::syntax_error:
if( errors_to_stdout )
std::cout << "Config: syntax error, line: " << parser.line << std::endl;
log << log1 << "Config: syntax error, line: " << parser.line << logend;
break;
}
}
bool Config::ReadConfig(bool errors_to_stdout_, bool stdout_is_closed)
{
errors_to_stdout = errors_to_stdout_;
if( config_file.empty() )
{
log << log2 << "Config: name of the config file is empty" << logend;
return false;
}
log << log2 << "Config: reading a config file" << logend;
parser.SplitSingle(true);
parser.UTF8(true); // config is always read in UTF-8
ConfParser::Status status = parser.Parse( config_file );
if( status == ConfParser::ok )
{
AssignValues(stdout_is_closed);
SetAdditionalVariables();
return true;
}
else
{
ShowError();
return false;
}
}
void Config::AssignValues(bool stdout_is_closed)
{
demonize = Bool(L"demonize", true);
user = AText(L"user");
group = AText(L"group");
additional_groups = Bool(L"additional_groups", true);
log_file = AText(L"log_file");
log_notify_file = AText(L"log_notify_file");
log_delimiter = Text(L"log_delimiter", L"---------------------------------------------------------------------------------");
fcgi_socket = AText(L"fcgi_socket");
fcgi_socket_chmod = Int(L"fcgi_socket_chmod", 0770);
fcgi_socket_user = AText(L"fcgi_socket_user");
fcgi_socket_group = AText(L"fcgi_socket_group");
log_level = Int(L"log_level", 1);
log_request = Int(L"log_request", 1);
log_save_each_line = Bool(L"log_save_each_line", false);
log_stdout = Bool(L"log_stdout", false);
log_db_query = Bool(L"log_db_query", false);
log_plugin_call = Bool(L"log_plugin_call", false);
post_file_max = Size(L"post_file_max", 8388608); // 8 MB
upload_dir = Text(L"upload_dir");
upload_dirs_chmod = Int(L"upload_dirs_chmod", 0750);
upload_files_chmod = Int(L"upload_files_chmod", 0640);
create_thumb = Bool(L"create_thumb", true);
thumb_mode = Int(L"thumb_mode", 2);
thumb_cx = Size(L"thumb_cx", 150);
thumb_cy = Size(L"thumb_cy", 150);
convert_cmd = Text(L"convert_cmd", L"/usr/local/bin/convert");
templates_dir = Text(L"templates_dir");
templates_dir_default = Text(L"templates_dir_default");
txt_templates_dir = Text(L"txt_templates_dir");
txt_templates_dir_default = Text(L"txt_templates_dir_default");
templates_fun_prefix = Text(L"templates_fun_prefix", L"fun_");
templates_fun_postfix = Text(L"templates_fun_postfix", L".html");
templates_index = Text(L"templates_index", L"index.html");
template_only_root_use_template_fun = Bool(L"template_only_root_use_template_fun", false);
http_session_id_name = AText(L"http_session_id_name");
db_database = AText(L"db_database");
db_user = AText(L"db_user");
db_pass = AText(L"db_pass");
item_url_empty = Text(L"item_url_empty");
base_server = Text(L"base_server");
base_url = Text(L"base_url");
base_url_static = Text(L"base_url_static");
base_url_common = Text(L"base_url_common");
NoLastSlash(base_server);
NoLastSlash(base_url);
NoLastSlash(base_url_static);
NoLastSlash(base_url_common);
priv_no_user = Text(L"priv_no_user", L"-- no user --");
priv_no_group = Text(L"priv_no_group", L"-- no group --");
session_max_idle = Int(L"session_max_idle", 10800); // 3h
session_remember_max_idle = Int(L"session_remember_max_idle", 16070400); // 3 months
session_file = AText(L"session_file");
session_max = Size(L"session_max", 1000000);
compression = Bool(L"compression", true);
compression_page_min_size = Int(L"compression_page_min_size", 512);
html_filter = Bool(L"html_filter", true);
html_filter_trim_white = Bool(L"html_filter_trim_white", true);
html_filter_break_lines = Int(L"html_filter_break_lines", 60);
html_filter_tabs = Size(L"html_filter_tabs", 2);
html_filter_orphans = Bool(L"html_filter_orphans", false);
html_filter_orphans_lang_str = AText(L"html_filter_orphans_lang", L"pl");
html_filter_orphans_mode_str = AText(L"html_filter_orphans_mode_str", L"nbsp");
locale_str = Text(L"locale", L"en");
locale_dir = Text(L"locale_dir");
locale_dir_default = Text(L"locale_dir_default");
title_separator = Text(L"title_separator", L" / ");
http_header_send_file = Text(L"http_header_send_file", L"X-LIGHTTPD-send-file");
password_min_size = Size(L"password_min_size", 5);
debug_info = Bool(L"debug_info", false);
editors_html_safe_mode = Bool(L"editors_html_safe_mode", true);
editors_html_safe_mode_skip_root = Bool(L"editors_html_safe_mode_skip_root", true);
plugins_dir = Text(L"plugins_dir", L"/usr/local/winix/plugins");
NoLastSlash(plugins_dir);
parser.ListText(L"plugins", plugin_file);
time_zone_offset = Int(L"time_zone_offset", 0);
time_zone_offset_guest = Int(L"time_zone_offset_guest", 0);
utf8 = Bool(L"utf8", true);
symlinks_follow_max = Size(L"symlinks_follow_max", 20);
ticket_form_prefix = Text(L"ticket_form_prefix", L"ticketparam");
}
void Config::SetAdditionalVariables()
{
SetHttpHost(base_url, base_url_http_host);
if( html_filter_orphans_lang_str == "pl" )
html_filter_orphans_lang = HTMLFilter::lang_pl;
else
if( html_filter_orphans_lang_str == "cz" )
html_filter_orphans_lang = HTMLFilter::lang_cz;
else
if( html_filter_orphans_lang_str == "sk" )
html_filter_orphans_lang = HTMLFilter::lang_sk;
else
html_filter_orphans_lang = HTMLFilter::lang_none;
if( html_filter_orphans_mode_str == "160" )
html_filter_orphans_mode = HTMLFilter::orphan_160space;
else
html_filter_orphans_mode = HTMLFilter::orphan_nbsp;
}
void Config::SetHttpHost(const std::wstring & in, std::wstring & out)
{
const char http[] = "http://";
const char https[] = "https://";
size_t http_len = sizeof(http) / sizeof(char) - 1;
size_t https_len = sizeof(https) / sizeof(char) - 1;
if( IsSubString(http, in.c_str()) )
out = in.substr(http_len);
else
if( IsSubString(https, in.c_str()) )
out = in.substr(https_len);
else
out.clear(); // if empty the RequestController::BaseUrlRedirect() returns false and no redirecting will be done
}
std::wstring Config::Text(const wchar_t * name)
{
return parser.Text(name);
}
std::wstring Config::Text(const wchar_t * name, const wchar_t * def)
{
return parser.Text(name, def);
}
std::wstring Config::Text(const std::wstring & name, const std::wstring & def)
{
return parser.Text(name, def);
}
std::string Config::AText(const wchar_t * name)
{
return parser.AText(name);
}
std::string Config::AText(const wchar_t * name, const wchar_t * def)
{
return parser.AText(name, def);
}
std::string Config::AText(const std::wstring & name, const std::wstring & def)
{
return parser.AText(name, def);
}
int Config::Int(const wchar_t * name)
{
return parser.Int(name);
}
int Config::Int(const wchar_t * name, int def)
{
return parser.Int(name, def);
}
int Config::Int(const std::wstring & name, int def)
{
return parser.Int(name, def);
}
size_t Config::Size(const wchar_t * name)
{
return parser.Size(name);
}
size_t Config::Size(const wchar_t * name, size_t def)
{
return parser.Size(name, def);
}
size_t Config::Size(const std::wstring & name, size_t def)
{
return parser.Size(name, def);
}
bool Config::Bool(const wchar_t * name)
{
return parser.Bool(name);
}
bool Config::Bool(const wchar_t * name, bool def)
{
return parser.Bool(name, def);
}
bool Config::Bool(const std::wstring & name, bool def)
{
return parser.Bool(name, def);
}
void Config::ListText(const wchar_t * name, std::vector<std::wstring> & list)
{
parser.ListText(name, list);
}
void Config::ListText(const std::wstring & name, std::vector<std::wstring> & list)
{
parser.ListText(name, list);
}
void Config::Print(std::ostream & out)
{
parser.Print(out);
}

356
core/config.h Executable file
View File

@@ -0,0 +1,356 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_config
#define headerfile_winix_core_config
#include <string>
#include "confparser.h"
#include "htmlfilter.h"
class Config
{
public:
// name of the config file
// this is the parameter passed to winix programm
std::string config_file;
// start as a demon (in the background)
// default: true
bool demonize;
// system user name (to which drop privileges)
// used only if winix is started as the root
std::string user;
// system group name (to which drop privileges)
// used only if winix is started as the root
std::string group;
// setting additional effective groups from /etc/group
// by using initgroups()
// used only if winix is started as the root
// default: true
bool additional_groups;
// log file name, log file name for notifications (sending emails, etc)
std::string log_file, log_notify_file;
// 1 - minimum
// 2 - (default)
// 3 - maximum - all logs
int log_level;
// logging to stdout too
// only if demonize is 'false'
// default: false
bool log_stdout;
// how many requests should be saved in the same time
// default: 1
int log_request;
// whether to save each line of the config (use it for debug purposes)
// default: false
bool log_save_each_line;
// logging db queries
// default: false
bool log_db_query;
// logging when a plugin function is called
// default: false
bool log_plugin_call;
// request delimiter in the log file, default "---------"
std::wstring log_delimiter;
// fast cgi: socket (unix domain)
std::string fcgi_socket;
// fast cgi: socket permissions
int fcgi_socket_chmod;
// fast cgi: owner of the socket
std::string fcgi_socket_user;
// fast cgi: group of the socket
std::string fcgi_socket_group;
std::wstring templates_dir;
std::wstring templates_dir_default; // html templates from winix
std::wstring txt_templates_dir;
std::wstring txt_templates_dir_default; // txt (notifications) templates from winix
// prefix and postfix for functions templates
// default:
// prefix: "fun_"
// postfix: ".html"
std::wstring templates_fun_prefix;
std::wstring templates_fun_postfix;
// main html template
// default: index.html
std::wstring templates_index;
// if true then only root can use 'template' function
// default: false
bool template_only_root_use_template_fun;
std::string db_database;
std::string db_user;
std::string db_pass;
std::string http_session_id_name;
// when the HOST_HTTP environment variable doesn't point into 'base_url' (the part 'http://' and the last slash is removed)
// the server will redirect into 'base_url' + 'REQUEST_URI'
// it's useful when you want to redirect from 'mydomain.tld' into 'www.mydomain.tld' etc.
bool base_url_redirect;
// string used in a place where is a user (or group) selected
std::wstring priv_no_user;
std::wstring priv_no_group;
// time in seconds when the user will be automatically logged out (iddle time)
int session_max_idle;
// time in seconds when the user will be automatically logged out (when he selected 'remember me' option)
// this time is usually greater than session_max_idle
int session_remember_max_idle;
// this file is used when the program is starting and ending
std::string session_file;
// how many sessions can be (zero turn off this checking)
// default: 1000000 (one milion)
size_t session_max;
// allow the html ouput to be compressed
bool compression;
// if the output is shorter than this value then it will not be compressed
int compression_page_min_size;
// plugins directory
// default: /usr/local/winix/plugins
std::wstring plugins_dir;
// plugins
// you can provide either a relative path (plugins_dir will be used)
// or a full path to a plugin
std::vector<std::wstring> plugin_file;
// should the html code be cleaned by the html filter
bool html_filter;
// should white characters be trimmed
bool html_filter_trim_white;
// when long lines (lines without a white character) should be break (inserted a space)
// default: after 60 non white characters will be put a space
// set zero to turn off
int html_filter_break_lines;
// how many spaces will be put at one tree level
// default: 2
size_t html_filter_tabs;
// use checking for 'orphans' for a specicic language
// default: false
bool html_filter_orphans;
// language for html orphans
// default: pl
// can be either: "pl" or "cz" or "sk"
std::string html_filter_orphans_lang_str;
HTMLFilter::Lang html_filter_orphans_lang;
// orphans mode
// either: "nbsp" or "160"
// default: "nbsp"
std::string html_filter_orphans_mode_str;
HTMLFilter::OrphanMode html_filter_orphans_mode;
// the url of a new empty item (if there is not the subject too)
std::wstring item_url_empty;
// maximum length of a file send by post multipart form
// 0 - not used
size_t post_file_max;
// directory for static files
std::wstring upload_dir;
// chmod of newly created directories (under upload_dir)
// default: 0750
int upload_dirs_chmod;
// chmod of newly created files (under upload_dir)
// default: 0640
int upload_files_chmod;
// create a thumbnail from an image
// default: true
bool create_thumb;
// the mode of creating a thumbnail
// width means thumb_cx, height means thumb_cy
// 1: Width given, height automagically selected to preserve aspect ratio.
// 2: Height given, width automagically selected to preserve aspect ratio.
// 3: Maximum values of height and width given, aspect ratio preserved.
// 4: Minimum values of width and height given, aspect ratio preserved.
// 5: Width and height emphatically given, original aspect ratio ignored.
// 6: Change as per widthxheight (3) but only if an image dimension exceeds a specified dimension.
// 7: Change dimensions only if both image dimensions are less than specified dimensions.
// default: 2
int thumb_mode;
// width of thumbnails
// default: 150
size_t thumb_cx;
// height of thumbnails
// default: 150
size_t thumb_cy;
// the convert program
// default: /usr/local/bin/convert
std::wstring convert_cmd;
// locale: en, pl
// default: en
std::wstring locale_str;
// directory with locale files
std::wstring locale_dir;
// directory with default locale files (those from winix)
std::wstring locale_dir_default;
// the main address of the server (e.g. someserver.com) (without the 'www' part etc)
std::wstring base_server;
// the main address of the site (e.g. http://www.someserver.com)
std::wstring base_url;
// static content not authorized by winix
std::wstring base_url_static;
// additional static server for common content (not authorized)
std::wstring base_url_common;
// separator used in <title> html tag
std::wstring title_separator;
// http header recognized by www server as a file to send back
// default: X-LIGHTTPD-send-file
std::wstring http_header_send_file;
// the minimum size of a password for new users (function: adduser)
// default: 5
size_t password_min_size;
// prints additional information (in the end of the html page as a commentary)
bool debug_info;
// in editors (emacs, ckeditor,...) the html will be filtered and unsafe tags
// will be dropped (script, frame, etc.)
// default: true;
bool editors_html_safe_mode;
// don't filter the html code for root
// default: true
// (if true the html code for root is not filtered)
bool editors_html_safe_mode_skip_root;
// temporarily we do not support time zones per user
// there is one offset for all users
// default: 0
int time_zone_offset;
// time zone offset for guests (not logged users)
// default: 0
int time_zone_offset_guest;
// charset used in templates, locales, logs etc.
// default: true (UTF-8)
// if false it means 8-bit ASCII
bool utf8;
// how many maximum symlinks can be followed
// (symlinks on directories as well)
// default: 20
size_t symlinks_follow_max;
// the prefix of a name of html form controls used in the ticket plugin
// default: ticketparam
std::wstring ticket_form_prefix;
/*
*/
// based on base_url
// set by SetAdditionalVariables()
// without the first part http:// (or https://) or the whole string is empty
std::wstring base_url_http_host;
Config();
bool ReadConfig(bool errors_to_stdout_, bool stdout_is_closed = true);
std::wstring Text(const wchar_t * name);
std::wstring Text(const wchar_t * name, const wchar_t * def);
std::wstring Text(const std::wstring & name, const std::wstring & def);
std::string AText(const wchar_t * name);
std::string AText(const wchar_t * name, const wchar_t * def);
std::string AText(const std::wstring & name, const std::wstring & def);
int Int(const wchar_t *);
int Int(const wchar_t * name, int def);
int Int(const std::wstring & name, int def);
size_t Size(const wchar_t *);
size_t Size(const wchar_t * name, size_t def);
size_t Size(const std::wstring & name, size_t def);
bool Bool(const wchar_t *);
bool Bool(const wchar_t * name, bool def);
bool Bool(const std::wstring & name, bool def);
void ListText(const wchar_t * name, std::vector<std::wstring> & list);
void ListText(const std::wstring & name, std::vector<std::wstring> & list);
// for debug
void Print(std::ostream & out);
private:
void ShowError();
void AssignValues(bool stdout_is_closed);
void SetHttpHost(const std::wstring & in, std::wstring & out);
void SetAdditionalVariables();
ConfParser parser;
std::string default_str;
int default_int;
bool default_bool;
bool errors_to_stdout;
};
#endif

729
core/confparser.cpp Executable file
View File

@@ -0,0 +1,729 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include <cstdlib>
#include <wchar.h>
#include "confparser.h"
#include "misc.h"
#include "utf8.h"
ConfParser::ConfParser()
{
// you can change this separators to what you want
// you shoud not use only white characters here (as expected by IsWhite() method)
// and new line characters ('\n')
separator = '=';
commentary = '#';
list_start = '(';
list_end = ')';
list_delimiter = ',';
split_single = false;
skip_empty = false;
use_escape_char = true;
input_as_utf8 = false;
default_str = L"";
default_int = 0;
default_size = 0;
default_bool = false;
}
void ConfParser::SplitSingle(bool split)
{
split_single = split;
}
void ConfParser::SkipEmpty(bool skip)
{
skip_empty = skip;
}
void ConfParser::UseEscapeChar(bool escape)
{
use_escape_char = escape;
}
ConfParser::Status ConfParser::Parse(const char * file_name)
{
line = 1;
table.clear();
table_single.clear();
file.clear();
file.open( file_name );
if( file )
{
status = ParseFile();
file.close();
}
else
{
status = cant_open_file;
}
return status;
}
ConfParser::Status ConfParser::Parse(const std::string & file_name)
{
return Parse(file_name.c_str());
}
ConfParser::Status ConfParser::Parse(const wchar_t * file_name)
{
Ezc::WideToUTF8(file_name, afile_name);
return Parse(afile_name.c_str());
}
ConfParser::Status ConfParser::Parse(const std::wstring & file_name)
{
return Parse(file_name.c_str());
}
ConfParser::Status ConfParser::ParseFile()
{
ReadChar();
SkipWhiteLines();
while( lastc != -1 )
{
if( !ReadVariable() )
return syntax_error;
if( lastc != separator )
return syntax_error;
if( !ReadValue() )
return syntax_error;
AddOption();
SkipWhite();
if( lastc != -1 && lastc != '\n' )
return syntax_error; // some characters have left at the end of an option
SkipWhiteLines();
}
return ok;
}
bool ConfParser::IsVariableChar(int c)
{
if( (c>='a' && c<='z') ||
(c>='A' && c<='Z') ||
(c>='0' && c<='9') ||
c=='.' || c==',' || c=='_' )
return true;
return false;
}
void ConfParser::AddOption()
{
if( value.empty() && skip_empty )
{
DeleteFromTable(variable);
DeleteFromTableSingle(variable);
return;
}
if( split_single && value.size() == 1 )
{
table_single[variable] = value[0];
DeleteFromTable(variable);
}
else
{
table[variable] = value;
DeleteFromTableSingle(variable);
}
}
void ConfParser::DeleteFromTable(const std::wstring & var)
{
Table::iterator i = table.find(var);
if( i != table.end() )
table.erase(i);
}
void ConfParser::DeleteFromTableSingle(const std::wstring & var)
{
TableSingle::iterator i = table_single.find(var);
if( i != table_single.end() )
table_single.erase(i);
}
bool ConfParser::ReadVariable()
{
variable.clear();
SkipWhite();
while( IsVariableChar(lastc) )
{
variable += lastc;
ReadChar();
}
SkipWhite();
return !variable.empty();
}
bool ConfParser::ReadValue()
{
value.clear();
ReadChar(); // skipping separator '='
SkipWhite();
if( lastc == list_start )
return ReadValueList();
else
return ReadValueNoList();
}
bool ConfParser::ReadValueList()
{
ReadChar(); // skipping first list character '('
SkipWhiteLines(); // lists can be split into several lines
while( lastc != -1 && lastc != list_end )
{
if( !ReadValueNoList(true) )
return false;
if( lastc == list_delimiter )
ReadChar();
SkipWhiteLines();
}
if( lastc != list_end )
return false;
ReadChar(); // skipping last list character ')'
SkipWhite();
return true;
}
bool ConfParser::ReadValueNoList(bool use_list_delimiter)
{
bool res;
value_item.clear();
if( lastc == '"' )
{
res = ReadValueQuoted(); // quoted value
if( res )
value.push_back(value_item);
}
else
{
res = ReadValueSimple(use_list_delimiter);
if( res && !value_item.empty() )
value.push_back(value_item);
}
return res;
}
bool ConfParser::ReadValueQuoted()
{
ReadChar(); // skipping the first quote
while( lastc != '"' && lastc != -1 )
{
if( use_escape_char && lastc == '\\' )
ReadChar();
value_item += lastc;
ReadChar();
}
if( lastc != '"' )
return false;
ReadChar(); // skipping the last quote
SkipWhite();
return true;
}
bool ConfParser::ReadValueSimple(bool use_list_delimiter)
{
int list_delimiter1 = -1;
int list_delimiter2 = -1;
if( use_list_delimiter )
{
list_delimiter1 = list_delimiter;
list_delimiter2 = list_end;
}
while( lastc!=-1 && lastc!='\n' && lastc!=commentary &&
lastc!=list_delimiter1 && lastc!=list_delimiter2 )
{
value_item += lastc;
ReadChar();
}
Trim(value_item);
SkipWhite();
return true;
}
int ConfParser::ReadUTF8Char()
{
int c;
bool correct;
lastc = -1;
do
{
Ezc::UTF8ToInt(file, c, correct);
if( !file )
return lastc;
}
while( !correct );
lastc = c;
if( lastc == '\n' )
++line;
return lastc;
}
int ConfParser::ReadASCIIChar()
{
lastc = file.get();
if( lastc == '\n' )
++line;
return lastc;
}
int ConfParser::ReadChar()
{
if( input_as_utf8 )
return ReadUTF8Char();
return ReadASCIIChar();
}
bool ConfParser::IsWhite(int c)
{
// dont use '\n' here
// 13 (\r) is at the end of a line in a dos file \r\n
// 160 is an unbreakable space
if( c==' ' || c=='\t' || c==13 || c==160 )
return true;
return false;
}
void ConfParser::SkipWhite()
{
while( IsWhite(lastc) || lastc == commentary )
{
if( lastc == commentary )
SkipLine();
else
ReadChar();
}
}
void ConfParser::SkipWhiteLines()
{
while( IsWhite(lastc) || lastc == commentary || lastc=='\n' )
{
if( lastc == commentary )
SkipLine();
else
ReadChar();
}
}
void ConfParser::SkipLine()
{
while( lastc != -1 && lastc != '\n' )
ReadChar();
}
void ConfParser::Trim(std::wstring & s)
{
std::wstring::size_type i;
if( s.empty() )
return;
// looking for white characters at the end
for(i=s.size()-1 ; i>0 && IsWhite(s[i]) ; --i);
if( i==0 && IsWhite(s[i]) )
{
// the whole string has white characters
s.clear();
return;
}
// deleting white characters at the end
if( i != s.size() - 1 )
s.erase(i+1, std::wstring::npos);
// looking for white characters at the beginning
for(i=0 ; i<s.size() && IsWhite(s[i]) ; ++i);
// deleting white characters at the beginning
if( i != 0 )
s.erase(0, i);
}
std::wstring ConfParser::Text(const wchar_t * name)
{
return Text(std::wstring(name), default_str);
}
std::wstring ConfParser::Text(const wchar_t * name, const wchar_t * def)
{
return Text(std::wstring(name), std::wstring(def));
}
std::wstring ConfParser::Text(const std::wstring & name, const std::wstring & def)
{
TableSingle::iterator i = table_single.find(name);
if( i == table_single.end() )
{
Table::iterator t = table.find(name);
if( t == table.end() || t->second.empty() )
return def;
return t->second[0];
}
return i->second;
}
std::string ConfParser::AText(const wchar_t * name)
{
std::wstring res = Text(name);
std::string ares;
Ezc::WideToUTF8(res, ares);
return ares;
}
std::string ConfParser::AText(const wchar_t * name, const wchar_t * def)
{
std::wstring res = Text(name, def);
std::string ares;
Ezc::WideToUTF8(res, ares);
return ares;
}
std::string ConfParser::AText(const std::wstring & name, const std::wstring & def)
{
std::wstring res = Text(name, def);
std::string ares;
Ezc::WideToUTF8(res, ares);
return ares;
}
int ConfParser::Int(const wchar_t * name)
{
return Int(std::wstring(name), default_int);
}
int ConfParser::Int(const wchar_t * name, int def)
{
return Int(std::wstring(name), def);
}
int ConfParser::ToInt(const std::wstring & value)
{
long res = (value[0] == '0')? wcstol(value.c_str() + 1, 0, 8) : wcstol(value.c_str(), 0, 10);
return static_cast<int>(res);
}
int ConfParser::Int(const std::wstring & name, int def)
{
TableSingle::iterator i = table_single.find(name);
if( i == table_single.end() )
{
Table::iterator t = table.find(name);
if( t == table.end() || t->second.empty() )
return def;
return ToInt(t->second[0]);
}
return ToInt(i->second);
}
size_t ConfParser::Size(const wchar_t * name)
{
return Size(std::wstring(name), default_size);
}
size_t ConfParser::Size(const wchar_t * name, size_t def)
{
return Size(std::wstring(name), def);
}
size_t ConfParser::ToSize(const std::wstring & value)
{
unsigned long res = (value[0] == '0')? wcstoul(value.c_str() + 1, 0, 8) : wcstoul(value.c_str(), 0, 10);
return static_cast<size_t>(res);
}
size_t ConfParser::Size(const std::wstring & name, size_t def)
{
TableSingle::iterator i = table_single.find(name);
if( i == table_single.end() )
{
Table::iterator t = table.find(name);
if( t == table.end() || t->second.empty() )
return def;
return ToSize(t->second[0]);
}
return ToSize(i->second);
}
bool ConfParser::Bool(const wchar_t * name)
{
return Bool(std::wstring(name), default_bool);
}
bool ConfParser::Bool(const wchar_t * name, bool def)
{
return Bool(std::wstring(name), def);
}
bool ConfParser::ToBool(const std::wstring & value)
{
return ( EqualNoCase(value.c_str(), L"true") ||
EqualNoCase(value.c_str(), L"yes") ||
EqualNoCase(value.c_str(), L"1")
);
}
bool ConfParser::Bool(const std::wstring & name, bool def)
{
TableSingle::iterator i = table_single.find(name);
if( i == table_single.end() )
{
Table::iterator t = table.find(name);
if( t == table.end() || t->second.empty() )
return def;
return ToBool(t->second[0]);
}
return ToBool(i->second);
}
void ConfParser::SetDefaultText(const std::wstring & def)
{
default_str = def;
}
void ConfParser::SetDefaultInt(int def)
{
default_int = def;
}
void ConfParser::SetDefaultSize(size_t def)
{
default_size = def;
}
void ConfParser::SetDefaultBool(bool def)
{
default_bool = def;
}
// in lists we don't use default values
void ConfParser::ListText(const wchar_t * name, std::vector<std::wstring> & list)
{
ListText(std::wstring(name), list);
}
void ConfParser::ListText(const std::wstring & name, std::vector<std::wstring> & list)
{
list.clear();
ConfParser::TableSingle::iterator i = table_single.find(name);
if( i != table_single.end() )
{
list.push_back(i->second);
return;
}
ConfParser::Table::iterator z = table.find(name);
if( z != table.end() )
{
list = z->second;
return;
}
}
void ConfParser::UTF8(bool utf)
{
input_as_utf8 = utf;
}
void ConfParser::Print(std::ostream & out)
{
TableSingle::iterator i1;
for(i1 = table_single.begin() ; i1 != table_single.end() ; ++i1)
{
Ezc::WideToUTF8(i1->first, out);
out << '=';
Ezc::WideToUTF8(i1->second, out);
out << std::endl;
}
Table::iterator i2;
Value::iterator i3;
for(i2 = table.begin() ; i2 != table.end() ; ++i2)
{
Ezc::WideToUTF8(i2->first, out);
out << '=';
for(i3 = i2->second.begin() ; i3 != i2->second.end() ; ++i3)
{
Ezc::WideToUTF8(*i3, out);
out << ',';
}
out << std::endl;
}
}

406
core/confparser.h Executable file
View File

@@ -0,0 +1,406 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfileconfparser
#define headerfileconfparser
#include <fstream>
#include <string>
#include <vector>
#include <map>
/*
A parser for parsing config files.
A config file can look like this:
variable1 = value 1
variable2 = " value 2 "
variable3 = (value 1, value 2)
variable4 = (" value 1 " , "value2", value 3)
sample of use:
ConfParser parser;
parser.Parse("/path/to/config");
if( parser.status == ConfParser::ok )
{
// the whole config we have in parser.table (parser.table_single)
}
config syntax:
option = list
list can consists of any number of items, if you're using more than one item you should
use brackets ()
for one item the brackets can be ommited:
option = value
white characters at the beginning of the value (and at the end) will be trimmed,
or you can use quotes:
option = "value"
option2 = "value with spaces at the end "
the form without quotes:
option = value
should be written in one line, so this is not allowed:
option =
value
you can use a new line characters only between brackets and quotes:
option = "this is
a multiline string"
option = ( value1,
value2 )
but there is one requirement: the first character " or ( should be in the same line,
so this is not allowed
option =
"this is wrong"
but this is ok:
option = "
that is ok"
empty lists:
option = ()
this creates an empty list: parser.table['option'].empty() == true
option =
this creates an empty list too (the same as previously)
option = ""
but this doesn't create an empty list, it creates a list with one (empty) item
commentaries:
# this is a commentary (until the end of the line)
option = value # this is a commentary too
commentaries are treated as white characters, other example:
option = ( # this is my list
"value 1" # this is a value one
value 2 # and this is a value two
) # end of my list
overwriting:
option1 = some value
option1 = other value
# always the last option is used so option1 is "other value"
list delimiter:
option1 = (value1, value2, value3)
option2 = ("value1", "value2", "value3")
above we're using a comma ',' as a list delimiter but when using quotes (second line)
the commas can be omitted:
option2 = ("value1" "value2" "value3")
white characters:
the name of an option cannot consist of white characters
some option = value # this is wrong
some_option = value # this is ok
which characters are allowed in an option name is defined by IsVariableChar() method
you can use white characters in values
option = value with spaces or tabs
white characters at the beginning and at the end will be trimmed,
so if you want them use quotes:
option = " other value with spaces "
special characters in quoted strings:
option = "this is a string with \" a quote inside"
the option will be: this is a string with " a quote inside
\\ - means one \
basically: \char produces char
so:
"\a" gives "a"
"\\" gives "\"
"\Z" gives "Z" and so on
you can call UseEscapeChar(false) to turn this off
*/
class ConfParser
{
public:
ConfParser();
/*
status of parsing
*/
enum Status { ok, cant_open_file, syntax_error };
/*
the last status of parsing, set by Parse() methods
*/
Status status;
/*
the main methods used to parse
file_name is the path to a file
*/
Status Parse(const char * file_name);
Status Parse(const std::string & file_name);
Status Parse(const wchar_t * file_name);
Status Parse(const std::wstring & file_name);
/*
a number of a line in which there is a syntax_error
*/
int line;
/*
this is the table which represents your config file
in the Table map: the first (key) is your 'option' and the second is 'list'
*/
typedef std::vector<std::wstring> Value;
typedef std::map<std::wstring, Value> Table;
Table table;
/*
if your config file consists mainly of single forms such as:
option = value
option2 = value2
then you can call SplitSingle(true) for not inserting single values to
previous 'table' but instead to 'table_single'
table_single as the second parameter takes only std::wstring (instead of the whole std::vector)
so you can save a little memory from not using std::vector
*/
typedef std::map<std::wstring, std::wstring> TableSingle;
TableSingle table_single;
/*
if your list consists of only one item, e.g:
option1 = value 1
option2 = "value 2"
option3 = ( "value 3" )
then if you call SplitSingle(true) then such values will be stored in
'table_single' instead of 'table' map
default: false
*/
void SplitSingle(bool split);
/*
if true then empty lists, e.g:
option =
option2 = ()
will be omitted (not inserted to 'table' or 'table_single')
default: false
*/
void SkipEmpty(bool skip);
/*
'\' character is used to escape other characters in a quoted string
so "some \t t\"ext" will produce "some t t"ext"
(this is only use in quoted string)
default: true
*/
void UseEscapeChar(bool escape);
/*
those methods are used to extract information from table or table_single
as a parameter they take the name of an option
and a default value (if there is no such a parameter),
they return appropriate value (either text, int or boolean)
(in lists they return the first item if exists)
*/
std::wstring Text(const wchar_t * name);
std::wstring Text(const wchar_t * name, const wchar_t * def);
std::wstring Text(const std::wstring & name, const std::wstring & def);
std::string AText(const wchar_t * name);
std::string AText(const wchar_t * name, const wchar_t * def);
std::string AText(const std::wstring & name, const std::wstring & def);
int Int(const wchar_t *);
int Int(const wchar_t * name, int def);
int Int(const std::wstring & name, int def);
size_t Size(const wchar_t *);
size_t Size(const wchar_t * name, size_t def);
size_t Size(const std::wstring & name, size_t def);
bool Bool(const wchar_t *);
bool Bool(const wchar_t * name, bool def);
bool Bool(const std::wstring & name, bool def);
/*
some default values
used in Text() Int() or Bool() when you don't explicitly set the default value
if you don't set it directly then:
default text is: "" (empty)
default int or size is: 0
default bool is: false
*/
void SetDefaultText(const std::wstring & def);
void SetDefaultInt(int def);
void SetDefaultSize(size_t def);
void SetDefaultBool(bool def);
/*
those methods are used to extract lists
note: if there is one option in table_single they will return it
*/
void ListText(const wchar_t * name, std::vector<std::wstring> & list);
void ListText(const std::wstring & name, std::vector<std::wstring> & list);
/*
if true then the input file is treated as UTF-8
*/
void UTF8(bool utf);
/*
printing the content
(for debug purposes)
*/
void Print(std::ostream & out);
private:
/*
last read variable (option)
*/
std::wstring variable;
/*
last read list item
*/
std::wstring value_item;
/*
last read list
*/
Value value;
/*
separator between a variable and a value, default: '='
*/
int separator;
/*
commentary char, default: '#'
*/
int commentary;
/*
list starting character, default: '('
*/
int list_start;
/*
list ending character, default: ')'
*/
int list_end;
/*
list delimiter, default: ','
*/
int list_delimiter;
/*
last read char
or -1 if the end
*/
int lastc;
/*
current file
*/
std::ifstream file;
/*
if true then lists with one item will be put into 'table_single' table
default: false
*/
bool split_single;
/*
if true then empty lists, e.g:
option =
option2 = ()
will be omitted (not inserted to 'table' or 'table_single')
default: false
*/
bool skip_empty;
/*
input file is in UTF-8
default: false
*/
bool input_as_utf8;
/*
if true you can use an escape character '\' in quoted values
*/
bool use_escape_char;
std::string afile_name;
std::wstring default_str;
int default_int;
size_t default_size;
bool default_bool;
int ToInt(const std::wstring & value);
size_t ToSize(const std::wstring & value);
bool ToBool(const std::wstring & value);
Status ParseFile();
void AddOption();
void DeleteFromTable(const std::wstring & var);
void DeleteFromTableSingle(const std::wstring & var);
bool ReadVariable();
bool ReadValue();
bool ReadValueList();
bool ReadValueNoList(bool use_list_delimiter = false);
bool ReadValueQuoted();
bool ReadValueSimple(bool use_list_delimiter = false);
int ReadUTF8Char();
int ReadASCIIChar();
int ReadChar();
bool IsWhite(int c);
bool IsVariableChar(int c);
void SkipWhite();
void SkipWhiteLines();
void SkipLine();
void Trim(std::wstring & s);
};
#endif

View File

@@ -1,477 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#include "content.h"
bool Content::Init()
{
templates.Read();
return true;
}
void Content::AddItem()
{
if( !request.session->is_logged )
return;
try
{
request.session->done = Done::added_item;
// request.item_table.resize(1);
// Item & item = request.item_table[0];
request.item.subject = request.PostVar("subject");
request.item.content = request.PostVar("content");
request.item.parent_id = data.dir.GetDirId( request.PostVar("directory") );
request.item.type = Item::file;
PrepareUrlSubject(request.item);
request.session->done_status = db.AddItem(request.item);
request.session->done_timer = 1;
// if( request.session->done_status != Request::added_item )
//request.item_table.resize(1);
//request.item_table[0] = request.item;
}
catch(const Error & e)
{
request.session->done_status = e;
}
}
void Content::EditItem()
{
if( !request.session->is_logged )
return;
try
{
request.session->done = Done::edited_item;
// request.item_table.resize(1);
// Item & item = request.item_table[0];
request.item.subject = request.PostVar("subject");
request.item.content = request.PostVar("content");
request.item.id = atol( request.PostVar("id").c_str() );
bool with_subject = false;
if( request.PostVar("old_subject") != request.item.subject )
with_subject = true;
request.item.parent_id = data.dir.GetDirId( request.PostVar("directory") );
request.item.type = Item::file;
PrepareUrlSubject(request.item);
request.session->done_status = db.EditItem(request.item, with_subject);
request.session->done_timer = 1;
}
catch(const Error & e)
{
request.session->done_status = e;
}
}
void Content::LogUser()
{
try
{
std::string & login = request.PostVar("login");
std::string & pass = request.PostVar("password");
long user_id;
if( db.CheckUser(login, pass, user_id) )
{
request.session->is_logged = true;
request.session->user_id = user_id;
request.session->user = login;
log << log2 << "User " << login << " (id: " << user_id << ") logged" << logend;
}
}
catch(const Error &)
{
}
}
void Content::MakeDirectoryStructure()
{
GetTable::size_type get_table_len = request.get_table.size();
long parent = -1;
for( get_index = 0 ; get_index < get_table_len ; ++get_index)
{
Item * pdir;
if( !data.dir.GetDir(request.get_table[get_index], parent, &pdir) )
break;
parent = pdir->id;
request.cur_dir_table.push_back( *pdir );
}
// parent - last directory (or -1 if none)
request.dir = parent;
data.dir.GetDirChilds(parent, request.dir_table);
}
Request::Result Content::StandardFunction(std::string & name)
{
Request::Result res = Request::err404;
// language polish
// in the future there'll be something here
// names of functions should not begin with an underscore '_'
if( name == "dodaj" )
res = Request::add_item;
else
if( name == "edytuj" )
res = Request::edit_item;
else
if( name == "id" )
res = Request::show_item_by_id;
else
if( name == "usun" )
res = Request::del_item;
else
if( name == "potwierdz" )
res = Request::confirm;
else
if( name == "wyloguj" )
res = Request::logout;
return res;
}
void Content::PrepareUrlSubject(Item & item)
{
SetUrlSubjectFromSubject(item);
if( StandardFunction(item.url_subject) != Request::err404 )
{
// names of functions should not begin with an underscore '_'
// and we can simply add one '_' at the beginning
// and the name will be unique
item.url_subject.insert(item.url_subject.begin(), '_');
}
}
bool Content::MakeGetCheckDir()
{
if( get_index == request.get_table.size() )
{
// request was for a directory
db.GetItems(request.item_table, item);
// !! temporarily
long default_id = -1;
if( request.cur_dir_table.empty() )
{
default_id = data.dir.root.default_item;
}
else
{
default_id = request.cur_dir_table.back().default_item;
}
if( default_id != -1 )
{
request.result = Request::show_item;
std::vector<Item>::iterator i;
for(i = request.item_table.begin() ; i != request.item_table.end() ; ++i)
{
if( i->id == default_id )
request.item_table[0] = *i;
}
request.item_table.resize(1);
}
else
if( data.one_item_is_showed &&
request.item_table.size() == 1 &&
request.item_table[0].type == Item::file )
{
request.result = Request::show_item;
}
else
{
request.result = Request::show_dir;
}
return true;
}
return false;
}
// zrobic tak ze gdzie podajemy cala liste aby nie ladowac contentu z bazy danych do itemow
void Content::MakeGet()
{
MakeDirectoryStructure();
item.Clear();
// request.dir is set by MakeDirectoryStructure()
item.parent_id = request.dir;
if( MakeGetCheckDir() )
return;
// request was for an item or a standard function
request.result = StandardFunction( request.get_table[get_index] );
if( request.result != Request::err404 )
{
// request for a standard function
++get_index;
return;
}
if( request.get_table[get_index].empty() )
// we do not have an empty url_subject
// err404 at the end
return;
// if we want to search by url_subject then request.get_table[get_index] should not be empty
item.url_subject = request.get_table[get_index++];
db.GetItems(request.item_table, item);
if( request.item_table.empty() )
// err404 at the end
return;
if( get_index == request.get_table.size() )
{
request.result = Request::show_item;
return;
}
// there is a standard function at the end
request.result = StandardFunction( request.get_table[get_index++] );
}
void Content::MakeEditItem()
{
if( !request.item_table.empty() )
request.item = request.item_table[0];
else
{
log << log1 << "Content: request.item_table should not be empty" << logend;
request.result = Request::err404;
}
}
void Content::AppendCurDir(std::string & dir)
{
std::vector<Item>::size_type a;
for(a=0 ; a<request.cur_dir_table.size() ; ++a)
{
dir += request.cur_dir_table[a].url_subject;
dir += '/';
}
}
void Content::MakeShowItemById()
{
if( get_index == request.get_table.size() )
{
request.result = Request::err404;
}
else
{
long id = atol( request.get_table[get_index++].c_str() );
db.GetItem(request.item_table, id);
if( request.item_table.empty() )
request.result = Request::err404;
else
{
request.result = Request::redirect;
std::string path;
data.dir.MakePath(request.item_table[0].parent_id, path);
request.str = data.base_url + path + request.item_table[0].url_subject;
}
}
}
void Content::MakeDelItem()
{
if( !request.session->is_logged )
return;
if( request.item_table.empty() )
{
request.result = Request::err404;
return;
}
if( get_index == request.get_table.size() )
{
request.CopyFirstItem();
request.session->item = request.item;
if( db.DelItem( request.item.id ) )
{
request.session->done = Done::deleted_item;
request.session->done_status = Error::ok;
log << log2 << "Content: deleted item: subject: " << request.item.subject << ", id: " << request.item.id << logend;
}
else
{
request.session->done = Done::deleted_item;
request.session->done_status = Error::db_no_item;
}
request.result = Request::redirect;
request.str = data.base_url;
AppendCurDir(request.str);
request.session->done_timer = 2;
}
else
{
if( StandardFunction( request.get_table[get_index++] ) == Request::confirm )
{
request.result = Request::del_item_confirm;
request.CopyFirstItem();
}
else
request.result = Request::err404;
}
}
void Content::MakeLogout()
{
if( request.session->is_logged )
{
log << log2 << "User " << request.session->user << " (id: " << request.session->user_id << ") logged out" << logend;
request.session->is_logged = false;
request.session->user.clear();
request.session->user_id = 0;
}
request.result = Request::redirect;
std::string path;
data.dir.MakePath(request.dir, path);
request.str = data.base_url + path;
if( !request.item_table.empty() )
request.str += request.item_table[0].url_subject;
request.session->done = Done::loggedout;
request.session->done_timer = 2;
}
void Content::MakeStandardFunction()
{
if( request.result == Request::edit_item )
{
MakeEditItem();
}
else
if( request.result == Request::show_item_by_id )
{
MakeShowItemById();
}
else
if( request.result == Request::del_item )
{
MakeDelItem();
}
else
if( request.result == Request::logout )
{
MakeLogout();
}
}
void Content::MakePost()
{
if( request.IsPostVar("add_item") )
AddItem();
else
if( request.IsPostVar("edit_item") )
EditItem();
else
if( request.IsPostVar("logging") )
LogUser();
}
void Content::Make()
{
MakePost();
MakeGet();
MakeStandardFunction();
templates.Generate();
// request.PrintGetTable();
//request.PrintEnv();
// request.PrintIn();
}

View File

@@ -1,73 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilecontent
#define headerfilecontent
#include <cstdlib>
#include <fcgiapp.h>
#include "templates.h"
#include "request.h"
#include "error.h"
#include "misc.h"
#include "db.h"
class Content
{
// index to request.get_table
// set after calling MakeDirectoryStructure()
// index of the last item which is not a directory (or is equal get_table.size())
GetTable::size_type get_index;
// temporarily object used for some purposes
Item item;
Templates templates;
void AddItem();
void EditItem();
void LogUser();
void MakeDirectoryStructure();
Request::Result StandardFunction(std::string & name);
void PrepareUrlSubject(Item & item);
bool MakeGetCheckDir();
void MakeEditItem();
void MakeShowItemById();
void MakeDelItem();
void MakeLogout();
void MakeStandardFunction();
void AppendCurDir(std::string & dir);
void MakePost();
void MakeGet();
public:
bool Init();
void Make();
};
#endif

View File

@@ -1,19 +1,19 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilecookieparser
#define headerfilecookieparser
#ifndef headerfile_winix_core_cookieparser
#define headerfile_winix_core_cookieparser
#include <fcgiapp.h>
#include "httpsimpleparser.h"
#include "requesttypes.h"
#include "log.h"
@@ -21,7 +21,7 @@ class CookieParser : public HttpSimpleParser
{
const char * cookie_string;
CookieTable & cookie_table;
CookieTab * cookie_tab;
protected:
@@ -41,21 +41,24 @@ protected:
// Cookie names are case insensitive according to section 3.1 of RFC 2965
ToLower(name);
std::pair<CookieTable::iterator, bool> res = cookie_table.insert( std::make_pair(name, value) );
std::pair<CookieTab::iterator, bool> res = cookie_tab->insert( std::make_pair(name, value) );
log << log2 << "Cookie, name: \"" << name << "\", value: \"" << value << "\"";
if( res.second == false )
log << log2 << " (skipped)";
{
res.first->second = value;
log << " (overwritten)";
}
log << log2 << logend;
log << logend;
}
public:
CookieParser(const char * cookie_string_, CookieTable & cookie_table_) : cookie_string(cookie_string_), cookie_table(cookie_table_)
CookieParser()
{
HttpSimpleParser::separator = ';';
HttpSimpleParser::value_can_be_quoted = true;
@@ -63,6 +66,16 @@ public:
HttpSimpleParser::recognize_special_chars = false;
}
// cookie_string can be null
void Parse(const char * cookie_string_, CookieTab & cookie_tab_)
{
cookie_string = cookie_string_;
cookie_tab = &cookie_tab_;
HttpSimpleParser::Parse();
}
};

34
core/cur.h Executable file
View File

@@ -0,0 +1,34 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_cur
#define headerfile_winix_core_cur
#include "request.h"
#include "session.h"
/*
current request and session
*/
struct Cur
{
Request * request;
Session * session;
// those pointers are never null, if there is no a session for the user
// the 'session' pointer pointers at a special temporary session
};
#endif

View File

@@ -1,46 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#include "data.h"
Data::Data()
{
// all these data will be reading from a config file
log_file = "cmslu.log";
fcgi_socket = "/var/cmslu/s1";
fcgi_socket_chmod = 0770;
fcgi_socket_user = "tomek";
fcgi_socket_group = "www";
log_level = 2;
log_stdout = true;
templates = "../httpd/templates"; // templates dir
default_index = "index.html";
http_session_id_name = "slimaczek_sid";
db_database = "tomek";
db_user = "tomek";
db_pass = "monitorekasd";
// !! add a method which will be adding a slash at the end of url-es
base_url = "http://s10.slimaczek.pl/"; // with a slash at the end
one_item_is_showed = true;
dir.root.default_item = 134;
}

View File

@@ -1,88 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfiledata
#define headerfiledata
#include <string>
#include <vector>
#include <map>
#include "misc.h"
#include "item.h"
#include "error.h"
#include "dir.h"
class Data
{
public:
// log file name
std::string log_file;
// 1 - minimum
// 2 - (default)
// 3 - maximum - all logs
int log_level;
// logging to stdout too
bool log_stdout;
// fast cgi: socket (unix domain)
std::string fcgi_socket;
// fast cgi: socket permissions
int fcgi_socket_chmod;
// fast cgi: owner of the socket
std::string fcgi_socket_user;
// fast cgi: group of the socket
std::string fcgi_socket_group;
std::string templates;
std::string default_index;
std::string db_database;
std::string db_user;
std::string db_pass;
std::string base_url;
std::string http_session_id_name;
Dir dir;
// if there is one item in a directory
// it will be showed
// (instead of showing directory contents)
bool one_item_is_showed;
Data();
};
extern Data data;
#endif

View File

@@ -1,668 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#include "db.h"
Db::Db()
{
pg_conn = 0;
}
Db::~Db()
{
Close();
}
void Db::Init(const std::string & d, const std::string & u, const std::string & p)
{
db_database = d;
db_user = u;
db_pass = p;
Connect();
}
void Db::Connect()
{
std::ostringstream buf;
buf << "dbname=" << db_database << " user=" << db_user << " password=" << db_pass;
pg_conn = PQconnectdb(buf.str().c_str());
if( !pg_conn )
log << log1 << "Db: Fatal error during connecting" << logend;
if( PQsetClientEncoding(pg_conn, "LATIN2") == -1 )
log << log1 << "Db: Can't set the proper client encoding" << logend;
}
void Db::Close()
{
if( pg_conn )
{
PQfinish(pg_conn);
pg_conn = 0;
}
}
void Db::AssertConnection()
{
if( !pg_conn )
{
log << log1 << "Db: Trying to connect into the database...";
Connect();
if( !pg_conn )
// logend from Connect()
throw Error(Error::db_fatal_error_during_connecting);
log << log1 << "ok" << logend;
}
if( PQstatus(pg_conn) != CONNECTION_OK )
{
log << log2 << "Db: connection into the database is lost, trying to recover..." << logend;
PQreset(pg_conn);
if( PQstatus(pg_conn) != CONNECTION_OK )
{
log << log2 << "no" << logend;
throw Error(Error::db_fatal_error_during_connecting);
}
else
{
log << log2 << "ok" << logend;
}
}
}
std::string Db::Escape(const std::string & s)
{
std::string result;
result.resize(s.length() * 2 + 1);
size_t len = PQescapeStringConn(pg_conn, const_cast<char*>( result.c_str() ), s.c_str(), s.length(), 0);
result.resize(len);
return result;
}
std::string Db::Escape(const char * s)
{
std::string result;
int len;
for(len=0 ; s[len] != 0 ; ++len);
result.resize(len * 2 + 1);
size_t len_new = PQescapeStringConn(pg_conn, const_cast<char*>( result.c_str() ), s, len, 0);
result.resize(len_new);
return result;
}
// ------------------
PGresult * Db::AssertQuery(const std::string & q)
{
PGresult * r = PQexec(pg_conn, q.c_str());
if( !r )
{
log << log1 << "Db: Problem with query: " << PQerrorMessage(pg_conn) << logend;
throw Error(Error::db_incorrect_query);
}
return r;
}
void Db::AssertResultStatus(PGresult * r, ExecStatusType t)
{
if( PQresultStatus(r) != t )
{
log << "Db: Incorrect result status: " << PQerrorMessage(pg_conn) << logend;
throw Error(Error::db_incorrent_result_status);
}
}
int Db::AssertColumn(PGresult * r, const char * column_name)
{
int c = PQfnumber(r, column_name);
if( c == -1 )
{
log << log1 << "Db: there is no column: " << column_name << logend;
throw Error(Error::db_no_column);
}
return c;
}
const char * Db::AssertValue(PGresult * r, int row, int col)
{
const char * res = PQgetvalue(r, row, col);
if( !res )
{
log << log1 << "Db: there is no such an item in the result, row:" << row << ", col:" << col << logend;
throw Error(Error::db_no_item);
}
return res;
}
void Db::ClearResult(PGresult * r)
{
if( r )
PQclear(r);
}
bool Db::CheckUser(std::string & login, std::string & password, long & user_id)
{
PGresult * r = 0;
bool user_ok = false;
try
{
AssertConnection();
std::ostringstream query;
query << "select id from core.user where login='" << Escape(login) << "' and password='" << Escape(password) << "';";
r = AssertQuery( query.str() );
AssertResultStatus(r, PGRES_TUPLES_OK);
int rows = PQntuples(r);
if( rows == 0 )
throw Error(Error::db_incorrect_login);
if( rows > 1 )
{
log << log1 << "Db: there is more than one user: " << login << " (with the same password)" << logend;
throw Error(Error::db_more_than_one_login);
}
int cuser_id = AssertColumn(r, "id");
const char * fuser_id = AssertValue(r, 0, cuser_id);
user_id = atol( fuser_id );
user_ok = true;
}
catch(const Error &)
{
}
ClearResult(r);
return user_ok;
}
bool Db::AddItemCreateUrlSubject(Item & item)
{
bool is_that_url;
PGresult * r = 0;
int index = 1;
const int max_index = 100;
char appendix[20];
appendix[0] = 0;
try
{
do
{
std::ostringstream query;
// this Escape can be put at the beginning (performance)
query << "select id from core.item where url_subject='" << Escape(item.url_subject) << appendix << "' and parent_id='" << item.parent_id << "';";
r = AssertQuery(query.str());
AssertResultStatus(r, PGRES_TUPLES_OK);
if( PQntuples(r) != 0 )
{
sprintf(appendix, "_(%d)", ++index);
is_that_url = true;
}
else
{
item.url_subject += appendix;
is_that_url = false;
}
ClearResult(r);
r = 0;
}
while( is_that_url && index <= max_index );
}
catch(const Error &)
{
is_that_url = true; // for return false
}
ClearResult(r);
return !is_that_url;
}
// for testing consistency
void Db::CheckAllUrlSubjectModifyItem(Item & item)
{
PGresult * r = 0;
try
{
std::ostringstream query;
query << "update core.item set url_subject=";
// url_subject
if( AddItemCreateUrlSubject(item) )
query << '\'' << Escape(item.url_subject) << '\'';
else
{
query << '\'' << item.id << '\'';
item.url_subject.clear();
}
query << " where id='" << item.id << "';";
r = AssertQuery(query.str());
AssertResultStatus(r, PGRES_COMMAND_OK);
}
catch(const Error &)
{
}
ClearResult(r);
}
// for checking consistency
void Db::CheckAllUrlSubject()
{
PGresult * r = 0;
Item item;
try
{
AssertConnection();
std::ostringstream query, query2;
query << "select id, subject from core.item where url_subject is null or url_subject=''";
r = AssertQuery(query.str());
AssertResultStatus(r, PGRES_TUPLES_OK);
int rows = PQntuples(r);
int cid = AssertColumn(r, "id");
int csubject = AssertColumn(r, "subject");
for(int i = 0 ; i<rows ; ++i)
{
item.id = atol( AssertValue(r, i, cid) );
item.subject = AssertValue(r, i, csubject);
CheckAllUrlSubjectModifyItem(item);
}
}
catch(const Error &)
{
}
ClearResult(r);
}
long Db::AssertCurrval(const char * table)
{
PGresult * r;
std::ostringstream query;
query << "select currval('" << table << "');";
r = AssertQuery(query.str());
AssertResultStatus(r, PGRES_TUPLES_OK);
if( PQntuples(r) != 1 )
{
log << log1 << "Db: error (currval) for table: " << table << ", " << PQerrorMessage(pg_conn) << logend;
throw Error(Error::db_err_currval);
}
long res = strtol( AssertValue(r, 0, 0), 0, 10 );
return res;
}
Error Db::AddItem(Item & item)
{
PGresult * r = 0;
Error result = Error::ok;
bool url_without_id = false;
try
{
AssertConnection();
std::ostringstream query;
query << "insert into core.item (subject, content, url_subject, type, parent_id) values (";
query << '\'' << Escape(item.subject) << "', ";
query << '\'' << Escape(item.content) << "', ";
// url_subject
url_without_id = AddItemCreateUrlSubject(item);
if( url_without_id )
{
query << '\'' << Escape(item.url_subject) << "', ";
}
else
{
query << "currval('core.item_id_seq')" << ", ";
}
query << '\'' << static_cast<int>(item.type) << "', ";
query << '\'' << item.parent_id << "' ";
query << ");";
r = AssertQuery(query.str());
AssertResultStatus(r, PGRES_COMMAND_OK);
item.id = AssertCurrval("core.item_id_seq");
if( !url_without_id )
ToString(item.url_subject, item.id);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::EditItem(Item & item, bool with_subject)
{
PGresult * r = 0;
Error result = Error::ok;
bool url_without_id = false;
try
{
AssertConnection();
std::ostringstream query;
query << "update core.item set (";
if( with_subject )
query << "subject, url_subject, ";
query << "content, type, parent_id) = (";
if( with_subject )
{
query << '\'' << Escape(item.subject) << "', ";
// url_subject
url_without_id = AddItemCreateUrlSubject(item);
if( url_without_id )
{
query << '\'' << Escape(item.url_subject) << "', ";
}
else
{
query << '\'' << item.id << "', ";
}
}
query << '\'' << Escape(item.content) << "', ";
query << '\'' << static_cast<int>(item.type) << "', ";
query << '\'' << item.parent_id << "' ";
query << ") where id='" << item.id << "';";
r = AssertQuery(query.str());
AssertResultStatus(r, PGRES_COMMAND_OK);
if( with_subject && !url_without_id )
ToString(item.url_subject, item.id);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
PGresult * Db::GetItemsQuery(Item & item_ref)
{
std::ostringstream query;
query << "select * from core.item where type!='0' and parent_id='" << item_ref.parent_id << "'";
if( item_ref.id != -1 )
query << " and id='" << item_ref.id << "'";
if( !item_ref.url_subject.empty() )
query << " and url_subject='" << Escape(item_ref.url_subject) << "'";
query << ';';
return AssertQuery(query.str());
}
void Db::GetItems(std::vector<Item> & item_table, Item & item_ref)
{
item_table.clear();
PGresult * r = 0;
try
{
AssertConnection();
r = GetItemsQuery(item_ref);
AssertResultStatus(r, PGRES_TUPLES_OK);
Item item;
int rows = PQntuples(r);
ItemColumns col;
col.SetColumns(r);
for(int i = 0 ; i<rows ; ++i)
{
col.SetItem(r, i, item);
item_table.push_back(item);
}
}
catch(const Error &)
{
}
ClearResult(r);
}
void Db::GetItem(std::vector<Item> & item_table, long id)
{
PGresult * r = 0;
try
{
AssertConnection();
std::ostringstream query;
query << "select * from core.item where type='1' and id='" << id << "';";
r = AssertQuery( query.str() );
AssertResultStatus(r, PGRES_TUPLES_OK);
Item item;
int rows = PQntuples(r);
if( rows > 1 )
log << log1 << "Db: we have more than one item with id: " << id << logend;
ItemColumns col;
col.SetColumns(r);
for(int i = 0 ; i<rows ; ++i)
{
col.SetItem(r, i, item);
item_table.push_back(item);
}
}
catch(const Error &)
{
}
ClearResult(r);
}
bool Db::DelItem(long id)
{
long rows = 0;
PGresult * r = 0;
try
{
AssertConnection();
std::ostringstream query;
query << "delete from core.item where type='1' and id='" << id << "';";
r = AssertQuery( query.str() );
AssertResultStatus(r, PGRES_COMMAND_OK);
const char * crows = PQcmdTuples(r);
if( crows )
{
rows = atol(crows);
if( rows > 1 )
log << log1 << "Db: more than one item were deleted" << logend;
}
}
catch(const Error &)
{
}
ClearResult(r);
return rows != 0;
}
void Db::GetDirs(DirContainer & dir_table)
{
PGresult * r = 0;
try
{
AssertConnection();
std::ostringstream query;
query << "select * from core.item where type='0';";
r = AssertQuery( query.str() );
AssertResultStatus(r, PGRES_TUPLES_OK);
Item item;
int rows = PQntuples(r);
ItemColumns col;
col.SetColumns(r);
for(int i = 0 ; i<rows ; ++i)
{
col.SetItem(r, i, item);
dir_table.PushBack( item );
}
}
catch(const Error &)
{
}
ClearResult(r);
}

119
core/db.h
View File

@@ -1,119 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilecoredb
#define headerfilecoredb
#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <libpq-fe.h>
#include <cstdio>
#include "log.h"
#include "item.h"
#include "misc.h"
#include "error.h"
#include "dircontainer.h"
class Db
{
protected:
PGconn * pg_conn;
std::string db_database, db_user, db_pass;
public:
Db();
~Db();
void Init(const std::string & database, const std::string & user, const std::string & pass);
void Connect();
void Close();
void AssertConnection();
std::string Escape(const std::string & s);
std::string Escape(const char * s);
PGresult * AssertQuery(const std::string & q);
void AssertResultStatus(PGresult * r, ExecStatusType t);
static int AssertColumn(PGresult * r, const char * column_name);
static const char * AssertValue(PGresult * r, int row, int col);
void ClearResult(PGresult * r);
bool CheckUser(std::string & login, std::string & password, long & user_id);
long AssertCurrval(const char * table);
bool AddItemCreateUrlSubject(Item & item);
Error AddItem(Item & item);
Error EditItem(Item & item, bool with_subject = true);
void CheckAllUrlSubjectModifyItem(Item & item);
void CheckAllUrlSubject();
PGresult * GetItemsQuery(Item & item_ref);
void GetItems(std::vector<Item> & item_table, Item & item_ref);
void GetItem(std::vector<Item> & item_table, long id);
bool DelItem(long id);
void GetDirs(DirContainer & dir_table);
struct ItemColumns
{
int id, subject, content, url_subject, type, parent_id, default_item;
void SetColumns(PGresult * r)
{
id = Db::AssertColumn(r, "id");
subject = Db::AssertColumn(r, "subject");
content = Db::AssertColumn(r, "content");
url_subject = Db::AssertColumn(r, "url_subject");
type = Db::AssertColumn(r, "type");
parent_id = Db::AssertColumn(r, "parent_id");
default_item = Db::AssertColumn(r, "default_item");
}
void SetItem(PGresult * r, long row, Item & item)
{
item.id = atol( Db::AssertValue(r, row, id) );
item.subject = Db::AssertValue(r, row, subject);
item.content = Db::AssertValue(r, row, content);
item.url_subject = Db::AssertValue(r, row, url_subject);
item.type = static_cast<Item::Type>( atoi( Db::AssertValue(r, row, type) ) );
item.parent_id = atol( Db::AssertValue(r, row, parent_id) );
item.default_item = atol( Db::AssertValue(r, row, default_item) );
}
};
}; // class Db
extern Db db;
#endif

View File

@@ -1,220 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#include "dir.h"
void Dir::Clear()
{
dir_table.Clear();
// !! temporarily not clearing
//root.Clear();
root.id = -1;
}
void Dir::ReadDirs()
{
Clear();
db.GetDirs(dir_table);
}
bool Dir::GetDir(const std::string & name, long parent, Item ** item)
{
DirContainer::ParentIterator i = dir_table.FindFirstParent(parent);
for( ; i!=dir_table.ParentEnd() ; i = dir_table.NextParent(i) )
if( i->second->url_subject == name )
{
*item = &(*i->second);
return true;
}
return false;
}
bool Dir::ExtractName(const char * & s, std::string & name)
{
name.clear();
// skipping first slashes (can be more than one)
for( ; *s == '/' ; ++s);
for( ; *s != 0 && *s != '/' ; ++s)
name += *s;
return !name.empty();
}
bool Dir::GetDir(const std::string & path, Item ** item)
{
long parent = -1;
std::string name;
const char * s = path.c_str();
Item * pitem = &root;
while( ExtractName(s, name) )
{
if( !GetDir(name, parent, &pitem) )
return false;
}
*item = pitem;
return true;
}
bool Dir::GetDirId(const std::string & path, long * id)
{
Item * pitem;
if( !GetDir(path, &pitem) )
return false;
*id = pitem->id;
return true;
}
bool Dir::GetDirId(const std::string & name, long parent, long * id)
{
Item * pitem;
if( !GetDir(name, parent, &pitem) )
return false;
*id = pitem->id;
return true;
}
bool Dir::IsDir(long id)
{
if( id == -1 )
// root directory
return true;
DirContainer::Iterator i = dir_table.FindId(id);
if( i == dir_table.End() )
return false;
return true;
}
bool Dir::GetDirChilds(long parent, std::vector<Item> & childs_table)
{
if( !IsDir(parent) )
return false;
DirContainer::ParentIterator i = dir_table.FindFirstParent(parent);
for( ; i != dir_table.ParentEnd() ; i = dir_table.NextParent(i) )
childs_table.push_back( *i->second );
return true;
}
// dodatkowo moze metoda AppendPath dodajaca sciezke do biezacego stringa?
// albo tutaj stringa nie czyscic?
// O(m * log n) (m- how many parts are in 'id')
bool Dir::MakePath(long id, std::string & path)
{
DirContainer::Iterator i;
path.clear();
while( true )
{
if( id == -1 )
return true;
i = dir_table.FindId(id);
if( i == dir_table.End() )
return false;
id = i->parent_id;
path.insert(path.begin(), '/');
path.insert(0, i->url_subject);
}
}
// with exceptions
Item * Dir::GetDir(const std::string & path)
{
Item * pitem;
if( !GetDir(path, &pitem) )
throw Error(Error::incorrect_dir);
return pitem;
}
Item * Dir::GetDir(const std::string & name, long parent)
{
Item * pitem;
if( !GetDir(name, parent, &pitem) )
throw Error(Error::incorrect_dir);
return pitem;
}
long Dir::GetDirId(const std::string & path)
{
long id;
if( !GetDirId(path, &id) )
throw Error(Error::incorrect_dir);
return id;
}
long Dir::GetDirId(const std::string & name, long parent)
{
long id;
if( !GetDirId(name, parent, &id) )
throw Error(Error::incorrect_dir);
return id;
}

View File

@@ -1,80 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfiledir
#define headerfiledir
#include <vector>
#include <map>
#include <string>
#include "item.h"
#include "error.h"
#include "log.h"
#include "db.h"
#include "dircontainer.h"
class Dir
{
private:
public: // !! temporarily
// id = -1;
Item root;
DirContainer dir_table;
// parent (or -1), item
//typedef std::multimap<long, Item> DirTable;
//DirTable dir_table;
bool ExtractName(const char * & s, std::string & name);
public:
void Clear();
void ReadDirs();
// without any exceptions
// these methods return false in a case the path or name (with a specific parent) are invalid
// we do not support '..' in a path (for security reason)
bool IsDir(long id);
bool GetDir(const std::string & path, Item ** item);
bool GetDir(const std::string & name, long parent, Item ** item);
bool GetDirId(const std::string & path, long * id);
bool GetDirId(const std::string & name, long parent, long * id);
bool GetDirChilds(long parent, std::vector<Item> & childs_table); // only returns dir-children
bool MakePath(long id, std::string & path);
// with an Error exception
// if the path or name are invalid these methods throw an exception
Item * GetDir(const std::string & path);
Item * GetDir(const std::string & name, long parent);
long GetDirId(const std::string & path);
long GetDirId(const std::string & name, long parent);
};
#endif

View File

@@ -1,22 +1,56 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "dircontainer.h"
#include "log.h"
std::wstring DirContainer::dir_etc = L"etc";
std::wstring DirContainer::dir_var = L"var";
// !! tutaj ostatecznie ustawic wartosc np okolo 100
// chwilowo do testow ustawione 2
DirContainer::DirContainer()
{
is_root = false;
is_etc = false;
is_var = false;
}
DirContainer::Iterator DirContainer::GetRoot()
{
if( !is_root )
return table.end();
return root_iter;
}
DirContainer::Iterator DirContainer::GetEtc()
{
if( !is_etc )
return table.end();
return etc_iter;
}
DirContainer::Iterator DirContainer::GetVar()
{
if( !is_var )
return table.end();
return var_iter;
}
DirContainer::Iterator DirContainer::Begin()
{
return table.begin();
@@ -31,7 +65,7 @@ DirContainer::Iterator DirContainer::End()
DirContainer::SizeType DirContainer::Size()
{
return table.size();
return table.size(); // !! warning: it has O(n)
}
bool DirContainer::Empty()
@@ -40,23 +74,132 @@ bool DirContainer::Empty()
}
void DirContainer::PushBack(const Item & item)
bool DirContainer::IsNameOfSpecialFolder(const std::wstring & name)
{
bool rebuild_indexes = false;
if( table.size() == table.capacity() )
rebuild_indexes = true;
table.push_back(item);
log << log2 << "DirCont: added item, id: " << item.id << ", parent_id: " << item.parent_id << logend;
if( rebuild_indexes )
RebuildIndexes();
else
AddIndexes( --table.end() );
return name == dir_etc || name == dir_var;
}
// looking for '/etc'
// 'root' is found beforehand
// CheckSpecialFolder() may not find everything (when the first is a special folder and then the root)
void DirContainer::FindSpecialFolders()
{
is_etc = false;
is_var = false;
if( !is_root )
return;
DirContainer::ParentIterator i = FindFirstChild(root_iter->id);
for( ; i!=ParentEnd() ; i = NextChild(i) )
{
if( i->second->url == dir_etc )
{
is_etc = true;
etc_iter = i->second;
}
else
if( i->second->url == dir_var )
{
is_var = true;
var_iter = i->second;
}
}
}
// this is used with PushBack() method
void DirContainer::CheckSpecialFolder(const Item & item, Iterator iter)
{
if( item.parent_id == -1 )
{
is_root = true;
root_iter = iter;
}
if( !is_root )
return;
if( item.parent_id==root_iter->id && item.url==dir_etc )
{
is_etc = true;
etc_iter = iter;
log << log2 << "DirCont: added special folder: /etc" << logend;
}
if( item.parent_id==root_iter->id && item.url==dir_var )
{
is_var = true;
var_iter = iter;
log << log2 << "DirCont: added special folder: /var" << logend;
}
}
DirContainer::Iterator DirContainer::PushBack(const Item & item)
{
if( item.parent_id == -1 && is_root )
{
log << log1 << "DirCont: more than one root dir - skipped, id: " << item.id << logend;
return root_iter;
}
Iterator last_iter = table.insert(table.end(), item);
CheckSpecialFolder(item, last_iter);
log << log2 << "DirCont: added dir, url: " << item.url << ", id: " << item.id << ", parent_id: " << item.parent_id << logend;
table_id.insert( std::make_pair(last_iter->id, last_iter) );
table_parent.insert( std::make_pair(last_iter->parent_id, last_iter) );
log << log3 << "DirCont: added indexes to dir, id: " << last_iter->id << ", parent_id: " << last_iter->parent_id << logend;
return last_iter;
}
bool DirContainer::ChangeParent(long dir_id, long new_parent_id)
{
Iterator i = FindId(dir_id);
if( i == table.end() )
return false;
if( i->parent_id == new_parent_id )
return true; // nothing to do
ParentIterator p = FindFirstChild(i->parent_id);
bool found = false;
for( ; p != table_parent.end() ; p = NextChild(p) )
{
if( p->second->id == dir_id )
{
table_parent.erase(p);
log << log3 << "DirCont: removed parent index to dir: " << i->id << logend;
i->parent_id = new_parent_id;
table_parent.insert( std::make_pair(new_parent_id, i) );
log << log3 << "DirCont: added parent index to dir, id: " << i->id << ", parent_id: " << i->parent_id << logend;
found = true;
if( IsNameOfSpecialFolder(i->url) )
FindSpecialFolders();
break; // that iterator (p) is only one
}
}
if( !found )
log << log1 << "DirCont: cannot find parent_id: " << i->parent_id << " in parent indexes" << logend;
return found;
}
@@ -65,6 +208,7 @@ void DirContainer::Clear()
table.clear();
table_id.clear();
table_parent.clear();
is_root = false;
}
@@ -82,34 +226,6 @@ return i->second;
void DirContainer::AddIndexes(Iterator item)
{
table_id.insert( std::make_pair(item->id, item) );
table_parent.insert( std::make_pair(item->parent_id, item) );
log << log2 << "DirCont: added indexes to item, id: " << item->id << ", parent_id: " << item->parent_id << logend;
}
void DirContainer::RebuildIndexes()
{
Iterator i;
log << log2 << "DirCont: rebuilding indexes" << logend;
table_id.clear();
table_parent.clear();
for(i=table.begin() ; i!=table.end() ; ++i)
AddIndexes( i );
log << log2 << "DirCont: indexes rebuilt, table.size: " << table.size() << ", table_id.size: " << table_id.size() << ", table_parent.size: " << table_parent.size() << logend;
}
DirContainer::ParentIterator DirContainer::ParentBegin()
{
return table_parent.begin();
@@ -135,7 +251,7 @@ bool DirContainer::ParentEmpty()
}
DirContainer::ParentIterator DirContainer::FindFirstParent(long parent)
DirContainer::ParentIterator DirContainer::FindFirstChild(long parent)
{
ParentIterator i = table_parent.lower_bound(parent);
@@ -146,7 +262,7 @@ return i;
}
DirContainer::ParentIterator DirContainer::NextParent(ParentIterator i)
DirContainer::ParentIterator DirContainer::NextChild(ParentIterator i)
{
if( i == table_parent.end() )
return table_parent.end();
@@ -159,3 +275,56 @@ DirContainer::ParentIterator DirContainer::NextParent(ParentIterator i)
return i;
}
bool DirContainer::DelById(long id)
{
TableId::iterator i = table_id.find(id);
if( i == table_id.end() )
{
log << log1 << "DirCont: delete: there is no directory with id: " << id << logend;
return false;
}
long parent_id = i->second->parent_id;
TableParent::iterator z = table_parent.lower_bound(parent_id);
bool found = false;
for( ; z != table_parent.end() && z->first == parent_id ; ++z )
{
if( z->second == i->second )
{
log << log2 << "DirCont: deleted directory id: " << id << ", url: " << i->second->url;
if( i->second->parent_id == -1 )
{
log << log2 << " (root directory)";
is_root = false;
}
log << log2 << logend;
table.erase(i->second);
log << log3 << "DirCont: deleted indexes into directory id: " << id << logend;
table_id.erase(i);
table_parent.erase(z);
found = true;
break;
}
}
if( !found )
{
log << log1 << "DirCont: can't find an index_parent into directory id: " << id << ", url: " << i->second->url << " (deleting skipped)" << logend;
return false;
}
return true;
}

View File

@@ -1,28 +1,28 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfiledircontainer
#define headerfiledircontainer
#ifndef headerfile_winix_core_dircontainer
#define headerfile_winix_core_dircontainer
#include <vector>
#include <list>
#include <map>
#include "item.h"
#include "log.h"
class DirContainer
{
public:
typedef std::vector<Item> Table;
typedef Table::iterator Iterator;
typedef Table::size_type SizeType;
typedef std::list<Item> Table;
typedef Table::iterator Iterator;
typedef Table::size_type SizeType;
typedef std::map<long, Iterator> TableId;
typedef std::multimap<long, Iterator> TableParent;
@@ -32,34 +32,63 @@ public:
DirContainer();
Iterator GetRoot();
Iterator GetEtc();
Iterator GetVar();
Iterator Begin();
Iterator End();
SizeType Size();
bool Empty();
void PushBack(const Item & item);
Iterator PushBack(const Item & item);
bool ChangeParent(long dir_id, long new_parent_id);
void Clear();
Iterator FindId(long id);
bool DelById(long id);
ParentIterator ParentBegin();
ParentIterator ParentEnd();
ParentSizeType ParentSize();
bool ParentEmpty();
ParentIterator FindFirstParent(long parent);
ParentIterator NextParent(ParentIterator pi);
ParentIterator FindFirstChild(long parent);
ParentIterator NextChild(ParentIterator pi);
bool IsNameOfSpecialFolder(const std::wstring & name);
void FindSpecialFolders();
private:
void AddIndexes(Iterator item);
void RebuildIndexes();
void CheckSpecialFolder(const Item & item, Iterator iter);
// main table with dirs
Table table;
// true if there is a root dir in the table
bool is_root;
// root
Iterator root_iter;
// true if there is a etc dir in the table
bool is_etc;
// etc
Iterator etc_iter;
// true if there is a var dir in the table
bool is_var;
// var
Iterator var_iter;
// indexes
TableId table_id;
TableParent table_parent;
// names of folders
static std::wstring dir_etc, dir_var;
};

659
core/dirs.cpp Executable file
View File

@@ -0,0 +1,659 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "dirs.h"
#include "error.h"
#include "log.h"
void Dirs::SetDb(Db * pdb)
{
db = pdb;
}
void Dirs::SetCur(Cur * pcur)
{
cur = pcur;
}
void Dirs::SetNotify(Notify * pnotify)
{
notify = pnotify;
}
void Dirs::Clear()
{
dir_tab.Clear();
}
bool Dirs::HasReadExecAccessForRoot(const Item & item)
{
// there must be at least one 'x' (for the root)
return (item.privileges & 01111) != 0; // !! in the future there'll be another 'x'
}
void Dirs::CheckRootDir()
{
DirContainer::Iterator i = dir_tab.GetRoot();
if( i != dir_tab.End() )
{
if( !HasReadExecAccessForRoot(*i) )
{
i->privileges = 0755;
log << log1 << "Dirs: there is no access for root (admin) to the root dir, setting 0755 for root dir" << logend;
db->EditPrivById(*i, i->id);
}
return;
}
log << log1 << "Dirs: there is no a root dir in the database (creating one)" << logend;
Item root;
root.type = Item::dir;
root.parent_id = -1;
root.user_id = -1;
root.group_id = -1;
root.privileges = 0755;
// !! upewnic sie ze baza nie zmieni url (gdyby wczesniej juz byl w bazie pusty url)
// !! zrobic jakis wyjatek do wprowadzania roota?
if( db->AddItem(root) == WINIX_ERR_OK )
{
dir_tab.PushBack(root);
}
}
void Dirs::ReadDirs()
{
Clear();
db->GetDirs(dir_tab);
CheckRootDir();
dir_tab.FindSpecialFolders();
}
bool Dirs::ExtractName(const wchar_t * & s, std::wstring & name)
{
name.clear();
// skipping first slashes (can be more than one)
for( ; *s == '/' ; ++s);
for( ; *s != 0 && *s != '/' ; ++s)
name += *s;
return !name.empty();
}
bool Dirs::IsDir(long id)
{
DirContainer::Iterator i = dir_tab.FindId(id);
if( i == dir_tab.End() )
return false;
return true;
}
// !! dac clearowanie childs_tab
// !! ewentualnie mozna dodac trzeci domyslny parametr bool clear_tab = true
bool Dirs::GetDirChilds(long parent, std::vector<Item*> & childs_tab)
{
if( parent != -1 && !IsDir(parent) )
return false;
DirContainer::ParentIterator i = dir_tab.FindFirstChild(parent);
for( ; i != dir_tab.ParentEnd() ; i = dir_tab.NextChild(i) )
childs_tab.push_back( &(*i->second) );
return true;
}
DirContainer::ParentIterator Dirs::FindFirstChild(long parent_id)
{
DirContainer::ParentIterator i = dir_tab.FindFirstChild(parent_id);
return i;
}
DirContainer::ParentIterator Dirs::NextChild(DirContainer::ParentIterator i)
{
return dir_tab.NextChild(i);
}
DirContainer::ParentIterator Dirs::ParentEnd()
{
return dir_tab.ParentEnd();
}
// dodatkowo moze metoda AppendPath dodajaca sciezke do biezacego stringa?
// albo tutaj stringa nie czyscic?
// O(m * log n) (m- how many parts are in 'id')
// path with a slash at the end
bool Dirs::MakePath(long id, std::wstring & path, bool clear_path)
{
DirContainer::Iterator i;
if( clear_path )
path.clear();
temp_path = '/';
while( true )
{
i = dir_tab.FindId(id);
if( i == dir_tab.End() ||
i->parent_id == id ) // means a loop (something wrong in the db)
{
// we don't change path if there is no such a directory
return false;
}
if( i->parent_id == -1 )
{
path += temp_path;
return true;
}
id = i->parent_id;
temp_path.insert(0, i->url);
temp_path.insert(temp_path.begin(), '/');
}
}
bool Dirs::ChangeParent(long dir_id, long new_parent_id)
{
return dir_tab.ChangeParent(dir_id, new_parent_id);
}
/*
checking whether dir_id has a parent parent_id (somewhere in the path)
*/
bool Dirs::HasParent(long dir_id, long parent_id)
{
DirContainer::Iterator i;
while( true )
{
i = dir_tab.FindId(dir_id);
if( i==dir_tab.End() || i->parent_id==-1 )
return false;
if( i->parent_id == parent_id )
return true;
dir_id = i->parent_id;
}
}
bool Dirs::CreateDirTab(long dir_id, std::vector<Item*> & out_dir_tab)
{
DirContainer::Iterator i;
out_dir_tab.clear();
do
{
i = dir_tab.FindId(dir_id);
if( i == dir_tab.End() )
return false;
if( out_dir_tab.empty() )
out_dir_tab.insert(out_dir_tab.end(), &(*i)); // !! I am not sure whether begin() can be used on an empty container
else
out_dir_tab.insert(out_dir_tab.begin(), &(*i));
dir_id = i->parent_id;
}
while( dir_id != -1 );
return true;
}
Item * Dirs::GetRootDir()
{
DirContainer::Iterator root = dir_tab.GetRoot();
if( root == dir_tab.End() )
return 0;
return &(*root);
}
Item * Dirs::GetEtcDir()
{
DirContainer::Iterator etc = dir_tab.GetEtc();
if( etc == dir_tab.End() )
return 0;
return &(*etc);
}
Item * Dirs::GetVarDir()
{
DirContainer::Iterator etc = dir_tab.GetVar();
if( etc == dir_tab.End() )
return 0;
return &(*etc);
}
Item * Dirs::GetDir(const std::wstring & name, long parent)
{
DirContainer::ParentIterator i = dir_tab.FindFirstChild(parent);
for( ; i!=dir_tab.ParentEnd() ; i = dir_tab.NextChild(i) )
if( i->second->url == name )
return &(*i->second);
return 0;
}
Item * Dirs::GetDir(const std::wstring & path)
{
DirContainer::Iterator root = dir_tab.GetRoot();
if( root == dir_tab.End() )
// ops, we do not have a root dir
return 0;
Item * pitem = &(*root);
std::wstring name; // !! dodac jako skladowa klasy
const wchar_t * s = path.c_str();
while( ExtractName(s, name) )
{
pitem = GetDir(name, pitem->id);
if( !pitem )
return 0;
}
return pitem;
}
Item * Dirs::GetDir(long id)
{
DirContainer::Iterator i = dir_tab.FindId(id);
if( i == dir_tab.End() )
return 0;
return &(*i);
}
Item * Dirs::AddDir(const Item & item)
{
return &(*dir_tab.PushBack(item));
}
size_t Dirs::AnalyzeDir(Item * pdir, const std::wstring & path, long & dir_id, std::wstring & dir)
{
size_t i = 0;
size_t old_i;
while( true )
{
dir_id = pdir->id;
// skipping slashes
for( ; i<path.size() && path[i] == '/' ; ++i );
if( i == path.size() )
return i; // end of the path
// creating a name
old_i = i;
analyze_temp.clear();
for( ; i<path.size() && path[i] != '/' ; ++i)
analyze_temp += path[i];
pdir = GetDir(analyze_temp, pdir->id);
if( !pdir )
return old_i; // analyze_temp is not a directory
dir += analyze_temp;
dir += '/';
}
}
/*
the path should begin with a slash
return values:
0 - directory exists
dir_id - id of the directory
dir - the path to the directory (with a slash at the end)
file - if not empty means a file name (we don't check if the file really exists)
1 - there is not a root dir
2 - the path is empty
3 - there is not such a directory
*/
int Dirs::AnalyzePath(const std::wstring & path, long & dir_id, std::wstring & dir, std::wstring & file)
{
Item * pdir = GetRootDir();
dir = '/';
file.clear();
if( !pdir )
return 1;
if( path.empty() )
return 2;
if( path[0] != '/' )
return 3;
size_t i = AnalyzeDir(pdir, path, dir_id, dir);
if( i < path.size() )
{
// checking if at least one slash has left
for(size_t a=i ; a < path.size() ; ++a)
if( path[a] == '/' )
return 3; // there is not such a directory
// the rest of the path is a file name
file = path.c_str() + i;
}
return 0;
}
// current_dir_tab can be the same container as out_dir_tab
void Dirs::CopyDirTab(const std::vector<Item*> & in, std::vector<Item*> & out)
{
if( &in != &out )
{
out.resize(in.size());
for(size_t i=0 ; i<in.size() ; ++i)
out[i] = in[i];
}
}
size_t Dirs::AnalyzeDir(std::vector<Item*> & dir_tab, const std::wstring & link_to)
{
if( dir_tab.empty() )
return 0;
size_t i = 0;
size_t old_i;
while( true )
{
// skipping slashes
for( ; i<link_to.size() && link_to[i] == '/' ; ++i);
if( i == link_to.size() )
return i; // end of the path
// creating a name
old_i = i;
analyze_temp.clear();
for( ; i<link_to.size() && link_to[i] != '/' ; ++i)
analyze_temp += link_to[i];
Item * pdir = GetDir(analyze_temp, dir_tab.back()->id);
if( !pdir )
return old_i; // analyze_temp is not a directory
dir_tab.push_back(pdir);
}
}
int Dirs::FollowLink(std::vector<Item*> & dir_tab, const std::wstring & link_to, std::wstring & out_item)
{
size_t i = AnalyzeDir(dir_tab, link_to);
if( i < link_to.size() )
{
// checking if at least one slash has left
for(size_t a=i ; a < link_to.size() ; ++a)
if( link_to[a] == '/' )
return 2; // there is not such a directory
// the rest of the path is a file name
out_item = link_to.c_str() + i;
return 1;
}
return 0;
}
/*
return codes:
ok:
0 - the link_to is a path to a directory (out_item skipped, out_dir_tab will not be empty)
1 - the link_to is a path to a file (out_item is used, out_dir_tab will not be empty)
error:
2 - incorrect link_to
3 - there is not a root dir
4 - current_dir_tab was empty
current_dir_tab can be the same container as out_dir_tab
link_to can be a relative path (without the first slash)
*/
int Dirs::FollowLink(const std::vector<Item*> & current_dir_tab, const std::wstring & link_to,
std::vector<Item*> & out_dir_tab, std::wstring & out_item)
{
temp_link_to = link_to; // link_to can be from the out_item and would be cleared next
out_item.clear();
if( current_dir_tab.empty() )
return 4;
if( temp_link_to.empty() )
{
CopyDirTab(current_dir_tab, out_dir_tab);
return 0;
}
if( temp_link_to[0] == '/' )
{
// temp_link_to is an absolute path
Item * pdir = GetRootDir();
if( !pdir )
return 3;
out_dir_tab.clear();
out_dir_tab.push_back(pdir);
}
else
{
// temp_link_to is a relative path
CopyDirTab(current_dir_tab, out_dir_tab);
}
return FollowLink(out_dir_tab, temp_link_to, out_item);
}
void Dirs::SplitPath(const std::wstring & path, std::wstring & dir, std::wstring & file)
{
std::wstring::size_type i;
dir.clear();
file.clear();
if( path.empty() )
// !! moze dir ustawic na '/' ?
return;
for( i=path.size()-1 ; i>0 && path[i]!='/' ; --i);
if( path[i] != '/' )
{
// we do not have any slashes '/'
file = path;
return;
}
dir.assign(path, 0, i + 1); // +1 means with a slash at the end
if( i < path.size() - 1 )
file.assign(path, i+1, path.size() - i - 1);
}
// !! dodac kasowanie z bazy
bool Dirs::DelDir(long dir_id)
{
return dir_tab.DelById(dir_id);
}
Error Dirs::AddDirectory(Item & item, bool add_to_dir_tab, Item ** pdir, int notify_code)
{
if( pdir )
*pdir = 0;
if( item.type != Item::dir )
return WINIX_ERR_DIR_EXPECTED;
Error status = db->AddItem(item);
if( status == WINIX_ERR_OK )
{
Item * d = AddDir(item);
if( add_to_dir_tab && !cur->request->dir_tab.empty() && cur->request->dir_tab.back()->id == item.parent_id )
cur->request->dir_tab.push_back(d);
if( pdir )
*pdir = d;
if( notify_code )
notify->ItemChanged(notify_code, item);
}
return status;
}
Item * Dirs::CreateVarDir()
{
Item * var = GetVarDir();
if( var )
return var;
Item v;
Item * root = GetRootDir();
if( root )
{
v.parent_id = root->id;
v.user_id = -1;
v.group_id = -1;
v.privileges = 0755;
v.subject = L"var";
v.url = L"var";
v.type = Item::dir;
AddDirectory(v, false, &var);
}
return var;
}
// printing first and last slash
void Dirs::LogDir(const std::vector<Item*> & dir_tab)
{
log << '/';
// skipping the first (root) directory
for(size_t i=1 ; i<dir_tab.size() ; ++i)
log << dir_tab[i]->url << '/';
}

103
core/dirs.h Executable file
View File

@@ -0,0 +1,103 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_dirs
#define headerfile_winix_core_dirs
#include <vector>
#include <map>
#include <string>
#include "item.h"
#include "dircontainer.h"
#include "db/db.h"
#include "request.h"
#include "notify/notify.h"
// we do not support '..' in a path (for simplicity and security reasons)
class Dirs
{
public:
void Clear();
void ReadDirs();
void SetCur(Cur * pcur);
void SetDb(Db * pdb);
void SetNotify(Notify * pnotify);
// these methods return false if there is no such a dir
bool IsDir(long dir_id);
bool GetDirChilds(long parent_id, std::vector<Item*> & childs_tab); // !! zamienic na GetChilds()
bool MakePath(long dir_id, std::wstring & path, bool clear_path = true);
bool ChangeParent(long dir_id, long new_parent_id);
bool HasParent(long dir_id, long parent_id);
bool DelDir(long dir_id);
bool CreateDirTab(long dir_id, std::vector<Item*> & out_dir_tab);
void LogDir(const std::vector<Item*> & dir_tab);
int AnalyzePath(const std::wstring & path, long & dir_id, std::wstring & dir, std::wstring & file);
int FollowLink(const std::vector<Item*> & current_dir_tab, const std::wstring & link_to,
std::vector<Item*> & out_dir_tab, std::wstring & out_item);
static void SplitPath(const std::wstring & path, std::wstring & dir, std::wstring & file);
DirContainer::ParentIterator FindFirstChild(long parent_id);
DirContainer::ParentIterator NextChild(DirContainer::ParentIterator i);
DirContainer::ParentIterator ParentEnd(); // !! pozostalo do zamiany na child
// these methods return null if there is no such a dir
// !! zmienic nazwy wskazujace ze operujemy tylko na lokalnej tablicy
Item * GetRootDir();
Item * GetEtcDir();
Item * GetVarDir();
Item * GetDir(const std::wstring & name, long parent);
Item * GetDir(const std::wstring & path);
Item * GetDir(long id);
Item * AddDir(const Item & item);
void CheckRootDir();
Item * CreateVarDir();
// !! jak juz wczesniejsze nazwy beda zmienione to tutaj damy AddDir() /AddDir() juz istnieje przeciez?/
Error AddDirectory(Item & item, bool add_to_dir_tab = false, Item ** pdir = 0, int notify_code = 0);
private:
Cur * cur;
Db * db;
Notify * notify;
DirContainer dir_tab;
std::wstring temp_path;
std::wstring temp_link_to;
size_t AnalyzeDir(Item * pdir, const std::wstring & path, long & dir_id, std::wstring & dir);
size_t AnalyzeDir(std::vector<Item*> & dir_tab, const std::wstring & link_to);
std::wstring analyze_temp;
void CopyDirTab(const std::vector<Item*> & in, std::vector<Item*> & out);
int FollowLink(std::vector<Item*> & dir_tab, const std::wstring & link_to, std::wstring & out_item);
bool ExtractName(const wchar_t * & s, std::wstring & name);
bool HasReadExecAccessForRoot(const Item & item);
};
#endif

View File

@@ -1,42 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#include "done.h"
Done::Done()
{
}
Done::Done(Code c) : code(c)
{
}
Done & Done::operator=(Code c)
{
code = c;
return *this;
}
bool Done::operator==(Code c) const
{
return code == c;
}
bool Done::operator!=(Code c) const
{
return code != c;
}

View File

@@ -1,45 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfiledone
#define headerfiledone
// what have been done
class Done
{
public:
enum Code
{
none,
added_item,
edited_item,
deleted_item,
loggedout
};
Done();
Done(Code c);
Done & operator=(Code c);
bool operator==(Code c) const;
bool operator!=(Code c) const;
private:
Code code;
};
#endif

View File

@@ -1,73 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#include "error.h"
Error::Error()
{
code = unknown;
}
Error::Error(Code c) : code(c)
{
}
Error::Error(int i)
{
code = static_cast<Code>(i);
}
Error::operator int() const
{
return static_cast<int>(code);
}
Error & Error::operator=(Code c)
{
code = c;
return *this;
}
bool Error::operator==(Code c) const
{
return code == c;
}
bool Error::operator!=(Code c) const
{
return code != c;
}
std::ostream & operator<<(std::ostream & out, const Error & e)
{
out << static_cast<int>(e.code);
return out;
}
Log & operator<<(Log & out, const Error & e)
{
out << static_cast<int>(e.code);
return out;
}

View File

@@ -1,70 +1,77 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfileerror
#define headerfileerror
#ifndef headerfile_winix_core_error
#define headerfile_winix_core_error
#include <iostream>
#include "log.h"
#define WINIX_ERR_OK 0
//#define WINIX_ERR_INCORRECT_PATH 1
//#define WINIX_ERR_NO_POSTVAR 2
#define WINIX_ERR_INCORRECT_DIR 3
#define WINIX_ERR_CANT_CHANGE_USER 4
#define WINIX_ERR_CANT_CHANGE_GROUP 5
#define WINIX_ERR_CANT_CHANGE_PRIVILEGES 6
#define WINIX_ERR_PERMISSION_DENIED 7
#define WINIX_ERR_NO_ROOT_DIR 8
#define WINIX_ERR_NO_FUNCTION 9
#define WINIX_ERR_NO_ITEM 10
#define WINIX_ERR_UNKNOWN_PARAM 11
#define WINIX_ERR_MOUNT_UNKNOWN 12
#define WINIX_ERR_UNKNOWN_FILESYSTEM 13
#define WINIX_ERR_NO_MOUNTPOINT 14
//#define WINIX_ERR_MOUNT_NO_PARAM 15
#define WINIX_ERR_NO_THREAD 16
#define WINIX_ERR_EMPTY 17
#define WINIX_ERR_SPAM 18
#define WINIX_ERR_INCORRECT_REBUS 19
class Error
{
#define WINIX_ERR_NO_BOUNDARY 20
#define WINIX_ERR_BROKEN_INPUT 21
#define WINIX_ERR_INPUT_TOO_LARGE 22
#define WINIX_ERR_CANT_CREATE_FILE 23
public:
#define WINIX_ERR_NO_TICKET 24
enum Code
{
ok = 0,
incorrect_path,
db_fatal_error_during_connecting,
db_incorrect_query,
db_incorrent_result_status,
db_no_column,
db_no_item,
db_incorrect_login,
db_more_than_one_login,
db_err_currval,
incorrect_dir,
unknown = 1000
};
#define WINIX_ERR_PASSWORDS_DIFFERENT 25
#define WINIX_ERR_PASSWORD_TOO_SHORT 26
#define WINIX_ERR_USER_EXISTS 27
#define WINIX_ERR_LOGIN_EMPTY 28
#define WINIX_DIFFERENT_MOUNT_POINTS 29
Error();
Error(Code c);
Error(int i);
Error & operator=(Code c);
operator int() const;
bool operator==(Code c) const;
bool operator!=(Code c) const;
friend std::ostream & operator<<(std::ostream & out, const Error & e);
friend Log & operator<<(Log & out, const Error & e);
#define WINIX_ERR_DB_FATAL_ERROR_DURING_CONNECTING 100
#define WINIX_ERR_DB_INCORRECT_QUERY 101
#define WINIX_ERR_DB_INCORRENT_RESULT_STATUS 102
#define WINIX_ERR_DB_NO_COLUMN 103
#define WINIX_ERR_DB_INCORRECT_LOGIN 104
#define WINIX_ERR_DB_MORE_THAN_ONE_LOGIN 105
#define WINIX_ERR_DB_ERR_CURRVAL 106
#define WINIX_ERR_FILE_EXPECTED 107
#define WINIX_ERR_DIR_EXPECTED 108
//#define WINIX_ERR_UNKNOWN 1000
#define WINIX_NOTHING_TO_DO 109
private:
Code code;
};
std::ostream & operator<<(std::ostream & out, const Error & e);
Log & operator<<(Log & out, const Error & e);
typedef int Error;

View File

@@ -1,24 +1,28 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilegetparser
#define headerfilegetparser
#ifndef headerfile_winix_core_getparser
#define headerfile_winix_core_getparser
#include "httpsimpleparser.h"
#include "requesttypes.h"
#include "misc.h"
#include "utf8.h"
class GetParser : public HttpSimpleParser
{
const char * get_string;
GetTable & get_table;
GetTab * get_tab;
std::wstring temp;
bool input_as_utf8;
protected:
@@ -33,22 +37,47 @@ protected:
virtual void Parameter(std::string &, std::string & value)
{
get_table.push_back(value);
log << log2 << "Get, value: \"" << value << "\"" << logend;
if( input_as_utf8 )
Ezc::UTF8ToWide(value, temp);
else
AssignString(value, temp);
get_tab->push_back(temp);
log << log2 << "Get, value: \"" << temp << "\"" << logend;
}
public:
GetParser(const char * get_string_, GetTable & get_table_) : get_string(get_string_), get_table(get_table_)
GetParser()
{
HttpSimpleParser::separator = '/';
HttpSimpleParser::read_name = false;
if( get_string && *get_string == separator ) // one '/' at the beginning
input_as_utf8 = false;
}
void UTF8(bool utf)
{
input_as_utf8 = utf;
}
// get_string_ can be null
void Parse(const char * get_string_, GetTab & get_tab_)
{
get_string = get_string_;
get_tab = &get_tab_;
if( get_string && *get_string == separator )
{
// skipping one '/' at the beginning
++get_string;
}
HttpSimpleParser::Parse();
}
};

43
core/group.h Executable file
View File

@@ -0,0 +1,43 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_group
#define headerfile_winix_core_group
#include <string>
#include <vector>
struct Group
{
long id;
std::wstring name; // group name
std::vector<long> members; // users id
Group()
{
Clear();
}
void Clear()
{
id = -1;
name.clear();
members.clear();
}
};
#endif

116
core/groups.cpp Executable file
View File

@@ -0,0 +1,116 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "groups.h"
Groups::Groups()
{
Clear();
}
void Groups::Clear()
{
table.Clear();
}
void Groups::ReadGroups(Db * db)
{
Clear();
db->GetGroups(table);
}
Group * Groups::GetGroup(long group_id)
{
Table::Iterator i = table.FindId(group_id);
if( i == table.End() )
return 0;
return &(*i);
}
Group * Groups::GetGroup(const std::wstring & name)
{
Table::Iterator i = table.FindName(name);
if( i == table.End() )
return 0;
return &(*i);
}
long Groups::GetGroupId(const std::wstring & name)
{
Group * pgroup = GetGroup(name);
if( !pgroup )
return -1;
return pgroup->id;
}
Groups::Iterator Groups::Begin()
{
return table.Begin();
}
Groups::Iterator Groups::End()
{
return table.End();
}
Groups::SizeType Groups::Size()
{
return table.Size();
}
Group & Groups::operator[](Groups::SizeType pos)
{
return table[pos];
}

53
core/groups.h Executable file
View File

@@ -0,0 +1,53 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_groups
#define headerfile_winix_core_groups
#include <map>
#include "group.h"
#include "ugcontainer.h"
#include "db/db.h"
class Groups
{
typedef UGContainer<Group> Table;
Table table;
public:
typedef Table::Iterator Iterator;
typedef Table::SizeType SizeType;
Groups();
void Clear();
void ReadGroups(Db * db);
Group * GetGroup(long group_id);
Group * GetGroup(const std::wstring & name);
long GetGroupId(const std::wstring & name);
Iterator Begin();
Iterator End();
SizeType Size();
Group & operator[](SizeType pos);
};
#endif

1231
core/htmlfilter.cpp Executable file

File diff suppressed because it is too large Load Diff

221
core/htmlfilter.h Executable file
View File

@@ -0,0 +1,221 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_htmlfilter
#define headerfile_winix_core_htmlfilter
#include <string>
// max length of a name of a html tag (with terminating null)
#define WINIX_HTMLFILTER_ITEM_MAXLEN 30
// depth of the html tree
#define WINIX_HTMLFILTER_STACK_MAXLEN 100
// length of a buffer used for printing
// it should be at least: WINIX_HTMLFILTER_ITEM_MAXLEN+3
#define WINIX_HTMLFILTER_BUFFER_MAXLEN 2048
/*!
very lightweight filter for html
(without using any dynamic memory - some memory is allocated only at the beginning - in ctors)
this filter has O(n) complexity over the whole html string
such tags as: <script> <pre> <textarea> are treated in a special way
all characters between the opening and closing tag (<script>....</script>) are untouched
if the filter finds that there are not closed tags it will close them,
if the filter finds a closing tag which doesn't have an opening tag - it will skip it
tags which don't need to be closed: meta, input, br, img, link
look at CheckExceptions() method
the filter recognizes xml simple tags (with / at the end) such as: <br />
*/
class HTMLFilter
{
public:
// for checking orphans
enum Lang
{
lang_pl,
lang_cz,
lang_sk,
lang_none
};
enum OrphanMode
{
orphan_nbsp, // putting "&nbsp;" string
orphan_160space // putting 160 ascii code
};
HTMLFilter();
HTMLFilter(const HTMLFilter & f);
HTMLFilter & operator=(const HTMLFilter & f);
~HTMLFilter();
// main methods used for filtering
void Filter(const wchar_t * in, std::wstring & out);
void Filter(const std::wstring & in, std::wstring & out);
// insert a white space into long lines
// only between html tags
// skipped in such tags: script, pre, textarea
// break_after - after how many characters insert a space (0 - off)
void BreakLines(size_t break_after_);
// trimming white characters (with new lines)
// at the beginning, at the end and in the middle of a string
// only between html tags
// at the beginning and at the end only one space is left
// skipped in such tags: script, pre, textarea
// false by default
void TrimWhite(bool trim);
// first tabs in a tree
// default: 2 (spaces)
// set 0 to turn off
void InsertTabs(size_t tabsize);
// check 'orphans' for the specicic language
// if an orphan is detected then the non-break space ("&nbsp;" or ascii 160 code) will be put
// default disable (lang_none)
void CheckOrphans(Lang lang_, OrphanMode mode = orphan_nbsp);
// skipping some unsafe tags
// (script, iframe, frame, frameset, applet, head, meta, html, link, body, ...)
void SafeMode(bool safe_mode_);
protected:
struct Item
{
wchar_t name[WINIX_HTMLFILTER_ITEM_MAXLEN];
size_t name_len;
enum Type
{
opening,
closing,
simple,
special,
none
} type;
// is there a new line after this tag
bool new_line;
void Clear();
Item();
};
// only this method have direct access to the output string
// you can easily change the output from a std::wstring to something else
virtual void Put(const wchar_t * str, const wchar_t * end);
Item & GetItem(size_t i);
Item & LastItem();
wchar_t ToLower(wchar_t c);
bool IsNameEqual(const wchar_t * name1, const wchar_t * name2);
bool IsNameEqual(const wchar_t * name1, const wchar_t * name2, size_t len);
bool IsLastTag(const wchar_t * name);
bool IsTagSafe(const wchar_t * tag);
int CheckOrphan(const wchar_t * str, const wchar_t * end, const wchar_t * orphan);
bool CheckOrphanTable(const wchar_t * str, const wchar_t * end, const wchar_t ** table, size_t o1, size_t o2);
bool CheckOrphanLangPl(const wchar_t * str, const wchar_t * end);
bool CheckOrphanLangCz(const wchar_t * str, const wchar_t * end);
bool CheckOrphan(const wchar_t * str, const wchar_t * end);
bool IsWhite(int c);
void SkipWhite();
void SkipWhiteLines();
void SkipWhiteWithFirstNewLine();
bool IsClosingTagForLastItem();
virtual bool IsOpeningTagMark();
virtual bool IsOpeningCommentaryTagMark();
size_t OpeningCommentaryTagMarkSize();
virtual bool IsClosingTagMark();
virtual bool IsClosingXmlSimpleTagMark();
bool SkipCommentaryTagIfExists();
const wchar_t * SkipItemCheckXmlSimple();
void PopStack();
bool PushStack();
virtual bool IsValidCharForName(int c);
void CheckNewLine();
virtual void CheckExceptions();
void CheckStackPrintRest();
void AddForgottenTags();
void CheckClosingTags();
virtual void ReadNormalTextSkipWhite(const wchar_t * & start, const wchar_t * & last_non_white);
void ReadNormalText();
bool PrintRest();
void PrintItem(const wchar_t * start, const wchar_t * end);
void ReadItemName();
bool ReadItem();
virtual void Init();
virtual void Deinit();
void Read();
size_t PutNormalTextTrimFillBuffer(const wchar_t * & str, const wchar_t * & end);
size_t PutNormalTextFillBuffer(const wchar_t * & str, const wchar_t * & end);
virtual void PutNormalText(const wchar_t * str, const wchar_t * end);
virtual void PutNormalTextTrim(const wchar_t * str, const wchar_t * end);
void PutLastTagWithClosingTag();
virtual void PutOpeningTagMark();
virtual void PutClosingTagMark();
virtual void PutTagName(const wchar_t * name);
virtual void PutOpeningTag(const wchar_t * start, const wchar_t * end);
virtual void PutClosingTag(const wchar_t * tag);
size_t PutTabsToBuffer(size_t index, size_t len);
size_t PutNonBreakSpaceToBuffer(size_t index);
void PutTabs(size_t len);
void PutNewLine();
const wchar_t * pchar;
Item empty;
Item * pstack; // stack pointer
size_t stack_len; // length of the stack
wchar_t * buffer; // buffer used when printing
std::wstring * out_string;
bool last_new_line;
size_t break_after; // insert a space into long lines after break_after characters
bool trim_white; // trimming white characters
size_t tab_size;
Lang lang; // current language for checking orphans
OrphanMode orphan_mode;
bool safe_mode; // skipping some unsafe tags
};
#endif

View File

@@ -1,8 +1,8 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
@@ -101,12 +101,16 @@ void HttpSimpleParser::CheckSpecialChar()
int c2 = GetChar();
if( c1==-1 || c2==-1 )
{
last_c = -1;
}
else
{
c1 = ParseHalfHex(c1);
c2 = ParseHalfHex(c2);
c1 = ParseHalfHex(c1);
c2 = ParseHalfHex(c2);
last_c = (c1 << 4) + c2;
last_c = (c1 << 4) + c2;
}
}
else
if( last_c == '+' )

View File

@@ -1,14 +1,14 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilehttpsimpleparser
#define headerfilehttpsimpleparser
#ifndef headerfile_winix_core_httpsimpleparser
#define headerfile_winix_core_httpsimpleparser
#include <string>
@@ -46,7 +46,7 @@ protected:
void TrimWhiteChars(std::string & s);
void CheckSpecialChar();
void Parse();
public:
@@ -60,12 +60,6 @@ public:
skip_white_chars = false;
recognize_special_chars = true;
}
void Parse();
};

72
core/item.cpp Executable file
View File

@@ -0,0 +1,72 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "item.h"
#include "misc.h"
Item::Item()
{
Clear();
}
void Item::SetDateToNow()
{
date_creation = Time(std::time(0));
date_modification = date_creation;
}
void Item::SetDateModifyToNow()
{
date_modification = Time(std::time(0));
}
void Item::Clear()
{
id = -1;
user_id = -1;
group_id = -1;
privileges = 0;
modification_user_id = -1;
guest_name.clear();
subject.clear();
content.clear();
modify_index = 0;
url.clear();
content_type = ct_formatted_text;
type = none;
parent_id = -1;
link_to.clear();
link_redirect = false;
content_id = -1;
ref = 1;
file_path.clear();
file_fs = -1;
file_type = WINIX_ITEM_FILETYPE_NONE;
has_thumb = false;
html_template.clear();
SetDateToNow();
}

View File

@@ -1,71 +1,104 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfileitem
#define headerfileitem
#ifndef headerfile_winix_core_item
#define headerfile_winix_core_item
#include <string>
#define WINIX_ITEM_FILETYPE_NONE 0
#define WINIX_ITEM_FILETYPE_IMAGE 1
#define WINIX_ITEM_FILETYPE_DOCUMENT 2
#define WINIX_ITEM_FILETYPE_UNKNOWN 3
struct Item
{
long id;
long parent_id;
long user_id;
long group_id;
std::wstring guest_name; // used as a user name when user_id is equal -1
long modification_user_id; // who has modified the item last (not taken into account when checking permissions)
int privileges;
tm date_creation;
tm date_modification;
std::wstring subject;
std::wstring content;
std::wstring url;
int modify_index;
enum ContentType
{
ct_text = 0,
ct_formatted_text,
ct_html,
ct_bbcode,
ct_raw
};
ContentType content_type;
std::string subject;
std::string content;
std::string url_subject;
enum Type
{
dir = 0,
file = 1,
symlink = 2,
none = 1000
};
Type type;
//item_type;
long parent_id;
long default_item;
// used when type is symlink or to a directory too (function 'default')
std::wstring link_to;
int link_redirect;
Item()
{
Clear();
}
// static file (if exists)
std::wstring file_path; // relative file path
int file_fs; // file system type where the file was saved
int file_type; // file type (none, image, doc, etc)
bool has_thumb;
void Clear()
{
id = -1;
subject.clear();
content.clear();
url_subject.clear();
type = none;
parent_id = -1;
default_item = -1;
}
std::wstring html_template;
// methods
Item();
void SetDateToNow();
void SetDateModifyToNow();
void Clear();
private:
// used by the database
long content_id; // content id in 'content' table
int ref; // content references
friend class Db;
friend class DbItemColumns;
};

112
core/lastcontainer.cpp Executable file
View File

@@ -0,0 +1,112 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2009, Tomasz Sowa
* All rights reserved.
*
*/
#include "lastcontainer.h"
#include "log.h"
#include "misc.h"
LastItem::LastItem()
{
user_id = 0;
ip = 0;
session_id = 0;
memset((char*)&start, 0, sizeof(start));
memset((char*)&end, 0, sizeof(end));
}
bool LastItem::IsLoggedOut()
{
if( end.tm_sec == 0 &&
end.tm_min == 0 &&
end.tm_hour == 0 &&
end.tm_mday == 0 &&
end.tm_mon == 0 &&
end.tm_year == 0 )
return false;
return true;
}
LastContainer::Iterator LastContainer::Begin()
{
return last_tab.begin();
}
LastContainer::Iterator LastContainer::End()
{
return last_tab.end();
}
LastContainer::Iterator LastContainer::FindNotLoggedOut(long user_id, long session_id)
{
LastTab::iterator i;
for(i=last_tab.begin() ; i!=last_tab.end() ; ++i)
{
if( i->user_id == user_id && i->session_id == session_id && !i->IsLoggedOut() )
return i;
}
return last_tab.end();
}
void LastContainer::UserLogin(long user_id, const std::wstring & name, unsigned int ip, long session_id)
{
LastTab::iterator i = FindNotLoggedOut(user_id, session_id);
if( i != last_tab.end() )
{
log << log1 << "LC: such a user and session_id exist, not added as a new one" << logend;
return;
}
if( last_tab.size() >= WINIX_LASTCONTAINER_TABLE_SIZE ) // last_tab has O(n) complexity
last_tab.erase(last_tab.begin());
LastItem li;
li.user_id = user_id;
li.name = name;
li.ip = ip;
li.session_id = session_id;
li.start = Time(std::time(0));
last_tab.insert(last_tab.end(), li);
log << log2 << "LC: added user: " << name << " into the last table" << logend;
}
void LastContainer::UserLogout(long user_id, long session_id)
{
LastTab::iterator i = FindNotLoggedOut(user_id, session_id);
if( i != last_tab.end() )
{
i->end = Time(std::time(0));
}
else
{
log << log4 << "LC: there is no such a user to log out" << logend;
}
}

77
core/lastcontainer.h Executable file
View File

@@ -0,0 +1,77 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2009, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_lastcontainer
#define headerfile_winix_core_lastcontainer
#include <string>
#include <list>
#include <cstring>
#include <ctime>
// how many items we store in the 'last' function
#define WINIX_LASTCONTAINER_TABLE_SIZE 100
struct LastItem
{
long user_id;
// additional we store the whole string-name
// (you can delete a user from the database but we can still print the name)
std::wstring name;
// ip address
unsigned int ip;
// session id (used when logging out)
long session_id;
// start logging and end logging
tm start;
tm end;
LastItem();
bool IsLoggedOut();
};
class LastContainer
{
public:
typedef std::list<LastItem> LastTab;
typedef LastTab::iterator Iterator;
public:
Iterator Begin();
Iterator End();
void UserLogin(long user_id, const std::wstring & name, unsigned int ip, long session_id);
void UserLogout(long user_id, long session_id);
private:
LastTab last_tab;
Iterator FindNotLoggedOut(long user_id, long session_id);
};
#endif

372
core/loadavg.cpp Executable file
View File

@@ -0,0 +1,372 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "loadavg.h"
#include "log.h"
LoadAvg::LoadAvg()
{
current1.Clear();
current5.Clear();
current15.Clear();
cache_load1 = 0.0;
cache_load5 = 0.0;
cache_load15 = 0.0;
cache_req_per_sec1 = 0.0;
cache_req_per_sec5 = 0.0;
cache_req_per_sec15 = 0.0;
was_stop_request = false;
CreateTable();
}
LoadAvg & LoadAvg::operator=(const LoadAvg & l)
{
current1 = l.current1;
current5 = l.current5;
current15 = l.current15;
cache_load1 = l.cache_load1;
cache_load5 = l.cache_load5;
cache_load15 = l.cache_load15;
cache_req_per_sec1 = l.cache_req_per_sec1;
cache_req_per_sec5 = l.cache_req_per_sec5;
cache_req_per_sec15 = l.cache_req_per_sec15;
was_stop_request = l.was_stop_request;
CreateTable();
return *this;
}
LoadAvg::LoadAvg(const LoadAvg & l)
{
operator=(l);
}
LoadAvg::~LoadAvg()
{
delete [] tab1;
delete [] tab5;
delete [] tab15;
}
void LoadAvg::CreateTable(size_t seconds, size_t granularity, Times* & tab, size_t & len)
{
len = (seconds / granularity) + 1; // rounding up (len mininum is 1)
tab = new Times[len];
for(size_t i=0 ; i<len ; ++i)
{
tab[i].Clear();
tab[i].dp = granularity; // at the beginning we assume the pause for all items
}
}
void LoadAvg::CreateTable()
{
CreateTable(60, WINIX_LOADAVG_GRANULARITY1, tab1, len1);
CreateTable(60 * 5, WINIX_LOADAVG_GRANULARITY5, tab5, len5);
CreateTable(60 * 15, WINIX_LOADAVG_GRANULARITY15, tab15, len15);
}
void LoadAvg::MoveTab(Times * tab, size_t len)
{
if( len > 1 )
{
for(size_t i=0 ; i<len-1 ; ++i)
tab[i] = tab[i+1];
}
tab[len-1].Clear();
}
void LoadAvg::UpdateTimer1()
{
MoveTab(tab1, len1);
tab1[len1-1] = current1;
current1.Clear();
cache_load1 = 0.0;
cache_req_per_sec1 = 0.0;
}
void LoadAvg::UpdateTimer5()
{
MoveTab(tab5, len5);
tab5[len5-1] = current5;
current5.Clear();
cache_load5 = 0.0;
cache_req_per_sec5 = 0.0;
}
void LoadAvg::UpdateTimer15()
{
MoveTab(tab15, len15);
tab15[len15-1] = current15;
current15.Clear();
cache_load15 = 0.0;
cache_req_per_sec15 = 0.0;
}
void LoadAvg::CheckTimers()
{
if( current1.dr + current1.dp > (double)WINIX_LOADAVG_GRANULARITY1 )
UpdateTimer1();
if( current5.dr + current5.dp > (double)WINIX_LOADAVG_GRANULARITY5 )
UpdateTimer5();
if( current15.dr + current15.dp > (double)WINIX_LOADAVG_GRANULARITY15 )
UpdateTimer15();
}
void LoadAvg::StartRequest()
{
clock_gettime(CLOCK_REALTIME, &start_req);
if( was_stop_request )
{
double dp = (start_req.tv_sec - stop_req.tv_sec);
dp += double(start_req.tv_nsec - stop_req.tv_nsec) / 1000000000.0; // make sure that tv_nsec has signed type
current1.dp += dp;
current5.dp += dp;
current15.dp += dp;
CheckTimers();
}
}
void LoadAvg::StopRequest()
{
clock_gettime(CLOCK_REALTIME, &stop_req);
double dr = (stop_req.tv_sec - start_req.tv_sec);
dr += double(stop_req.tv_nsec - start_req.tv_nsec) / 1000000000.0; // make sure that tv_nsec has signed type
current1.dr += dr;
current5.dr += dr;
current15.dr += dr;
current1.req += 1;
current5.req += 1;
current15.req += 1;
log << log2 << "LA: request took: " << dr << "s" << logend;
was_stop_request = true;
}
void LoadAvg::SumTab(Times * tab, size_t len, double expected, Times & t)
{
size_t i = len;
while( i-- > 0 && t.dr+t.dp < expected )
{
t.dr += tab[i].dr;
t.dp += tab[i].dp;
t.req += tab[i].req;
}
}
void LoadAvg::Calculate1()
{
Times t = current1;
SumTab(tab1, len1, 60.0, t);
if( t.dr+t.dp == 0.0 )
{
cache_load1 = 0.0;
cache_req_per_sec1 = 0.0;
}
else
{
cache_load1 = t.dr / (t.dr+t.dp);
cache_req_per_sec1 = t.req / (t.dr+t.dp);
}
}
void LoadAvg::Calculate5()
{
Times t = current5;
SumTab(tab5, len5, 60.0 * 5, t);
if( t.dr+t.dp == 0.0 )
{
cache_load5 = 0.0;
cache_req_per_sec5 = 0.0;
}
else
{
cache_load5 = t.dr / (t.dr+t.dp);
cache_req_per_sec5 = t.req / (t.dr+t.dp);
}
}
void LoadAvg::Calculate15()
{
Times t = current15;
SumTab(tab15, len15, 60.0 * 15, t);
if( t.dr+t.dp == 0.0 )
{
cache_load15 = 0.0;
cache_req_per_sec15 = 0.0;
}
else
{
cache_load15 = t.dr / (t.dr+t.dp);
cache_req_per_sec15 = t.req / (t.dr+t.dp);
}
}
double LoadAvg::LoadAvgNow()
{
double load = 0.0;
double dr = current1.dr;
double dp = current1.dp;
if( tab1[len1-1].dr + tab1[len1-1].dp < WINIX_LOADAVG_GRANULARITY1 * 2 )
{
dr += tab1[len1-1].dr;
dp += tab1[len1-1].dp;
}
if( dr + dp != 0.0 )
load = dr / (dr + dp);
return load;
}
double LoadAvg::LoadAvg1()
{
if( cache_load1 != 0.0 )
return cache_load1;
Calculate1();
return cache_load1;
}
double LoadAvg::LoadAvg5()
{
if( cache_load5 != 0.0 )
return cache_load5;
Calculate5();
return cache_load5;
}
double LoadAvg::LoadAvg15()
{
if( cache_load15 != 0.0 )
return cache_load15;
Calculate15();
return cache_load15;
}
double LoadAvg::ReqPerSecNow()
{
double req_per_sec = 0.0;
double dr = current1.dr;
double dp = current1.dp;
double req = current1.req;
if( tab1[len1-1].dr + tab1[len1-1].dp < WINIX_LOADAVG_GRANULARITY1 * 2 )
{
dr += tab1[len1-1].dr;
dp += tab1[len1-1].dp;
req += tab1[len1-1].req;
}
if( dr + dp != 0.0 )
req_per_sec = req / (dr + dp);
return req_per_sec;
}
double LoadAvg::ReqPerSec1()
{
if( cache_req_per_sec1 != 0.0 )
return cache_req_per_sec1;
Calculate1();
return cache_req_per_sec1;
}
double LoadAvg::ReqPerSec5()
{
if( cache_req_per_sec5 != 0.0 )
return cache_req_per_sec5;
Calculate5();
return cache_req_per_sec5;
}
double LoadAvg::ReqPerSec15()
{
if( cache_req_per_sec15 != 0.0 )
return cache_req_per_sec15;
Calculate15();
return cache_req_per_sec15;
}

114
core/loadavg.h Executable file
View File

@@ -0,0 +1,114 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_loadavg
#define headerfile_winix_core_loadavg
#include <ctime>
// in seconds
#define WINIX_LOADAVG_GRANULARITY1 2
#define WINIX_LOADAVG_GRANULARITY5 15
#define WINIX_LOADAVG_GRANULARITY15 45
class LoadAvg
{
public:
LoadAvg();
~LoadAvg();
LoadAvg & operator=(const LoadAvg & l);
LoadAvg(const LoadAvg & l);
void StartRequest();
void StopRequest();
double LoadAvgNow(); // load average withing last WINIX_LOADAVG_GRANULARITY1 seconds
double LoadAvg1();
double LoadAvg5();
double LoadAvg15();
double ReqPerSecNow();
double ReqPerSec1();
double ReqPerSec5();
double ReqPerSec15();
private:
struct Times
{
double dr; // time for the request (in seconds)
double dp; // time for the pause between requestes (in seconds)
long req; // how many requests
void Clear()
{
dr = 0.0;
dp = 0.0;
req = 0;
}
Times & operator=(const Times & t)
{
dr = t.dr;
dp = t.dp;
req = t.req;
return *this;
}
};
void CheckTimers();
void UpdateTimer1();
void UpdateTimer5();
void UpdateTimer15();
Times current1;
Times current5;
Times current15;
void CreateTable(size_t seconds, size_t granulatiry, Times* & tab, size_t & len);
void CreateTable();
void MoveTab(Times * tab, size_t len);
void SumTab(Times * tab, size_t len, double expected, Times & t);
void Calculate1();
void Calculate5();
void Calculate15();
bool was_stop_request;
timespec start_req, stop_req;
Times * tab1;
size_t len1;
Times * tab5;
size_t len5;
Times * tab15;
size_t len15;
double cache_load1;
double cache_load5;
double cache_load15;
double cache_req_per_sec1;
double cache_req_per_sec5;
double cache_req_per_sec15;
};
#endif

View File

@@ -1,149 +1,319 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "log.h"
#include <ctime>
#include <string.h>
#include "utf8.h"
Log::Log()
{
log_level = 1;
current_level = 2;
log_file = "cmslu.log";
log_stdout = true;
current_level = 100; // nothing to log (call Init() first)
request = 0;
max_requests = 1;
lines = 0;
max_lines = 5000;
log_file_open = false;
}
void Log::Init(int log_l, const std::string & log_f, bool log_std)
Log::~Log()
{
log_level = log_l;
log_file = log_f;
log_stdout = log_std;
SaveLogAndClear();
}
void Log::Init(int log_level_, bool save_each_line_, const std::string & log_file_, bool log_std, int log_max_requests)
{
log_level = log_level_;
log_file = log_file_;
log_stdout = log_std;
max_requests = log_max_requests;
save_each_line = save_each_line_;
// don't open the file here
// because it would be created with the root as an owner
}
void Log::OpenFile()
{
if( !log_file.empty() )
{
file.open( log_file.c_str(), std::ios_base::out | std::ios_base::app );
log_file_open = true;
}
}
void Log::PutDate(Manipulators m)
{
// logs are related to localtime
time_t t = std::time(0);
std::tm * loct = std::localtime(&t);
// zrobic templeta z tych metod
// i dla const char * zrobic specjalizacje
char buffer[70];
sprintf(buffer, "%d.%02d.%02d %02d:%02d:%02d ", int(loct->tm_year + 1900),
int(loct->tm_mon + 1),
int(loct->tm_mday),
int(loct->tm_hour),
int(loct->tm_min),
int(loct->tm_sec));
Log & Log::operator<<(const char * s)
(*this) << m << buffer;
}
Log & Log::operator<<(const void * s)
{
if( !s )
if( current_level > log_level )
return *this;
buffer << s;
return *this;
}
Log & Log::operator<<(const char * s)
{
if( current_level > log_level )
return *this;
if( !s )
return *this;
buffer << s;
return *this;
}
Log & Log::operator<<(const std::string & s)
{
buffer << s;
if( current_level > log_level )
return *this;
return *this;
buffer << s;
return *this;
}
Log & Log::operator<<(const std::string * s)
{
if( current_level > log_level )
return *this;
buffer << *s;
return *this;
}
Log & Log::operator<<(const wchar_t * s)
{
if( current_level <= log_level )
{
if( s )
buffer << s;
}
return *this;
}
Log & Log::operator<<(const std::wstring & s)
{
if( current_level <= log_level )
{
buffer << s;
}
return *this;
}
Log & Log::operator<<(const std::wstring * s)
{
if( current_level <= log_level )
{
buffer << *s;
}
return *this;
}
Log & Log::operator<<(int s)
{
buffer << s;
if( current_level <= log_level )
{
buffer << s;
}
return *this;
return *this;
}
Log & Log::operator<<(long s)
{
buffer << s;
if( current_level <= log_level )
{
buffer << s;
}
return *this;
return *this;
}
/*
Log & Log::operator<<(void * s)
{
buffer << s;
return *this;
}
*/
Log & Log::operator<<(char s)
{
buffer << s;
if( current_level <= log_level )
{
buffer << s;
}
return *this;
return *this;
}
Log & Log::operator<<(size_t s)
{
buffer << s;
if( current_level <= log_level )
{
buffer << s;
}
return *this;
return *this;
}
Log & Log::operator<<(double s)
{
if( current_level <= log_level )
{
buffer << s;
}
return *this;
}
Log & Log::operator<<(Manipulators m)
{
switch(m)
{
case logend:
SaveLog();
buffer.str( "" );
break;
switch(m)
{
case logend:
if( current_level <= log_level )
{
buffer << '\n';
lines += 1;
case log1:
current_level = 1;
break;
if( save_each_line )
SaveLogAndClear();
}
break;
case log2:
current_level = 2;
break;
case logsave:
SaveLogAndClear();
break;
case log3:
current_level = 3;
break;
case logendrequest:
if( ++request >= max_requests || lines > max_lines )
SaveLogAndClear();
break;
case log1:
current_level = 1;
break;
case log2:
current_level = 2;
break;
case log3:
current_level = 3;
break;
}
case log4:
current_level = 4;
break;
}
return *this;
return *this;
}
void Log::SystemErr(int err)
{
(*this) << "errno: " << err;
const char * err_msg = strerror(err);
if( err_msg )
(*this) << " (" << err_msg << ")";
}
void Log::SaveLogAndClear()
{
SaveLog();
buffer.Clear();
request = 0;
lines = 0;
}
void Log::SaveLog()
{
int attempt = 2;
if( buffer.Str().empty() )
return;
if( current_level > log_level )
return;
if( log_stdout )
Ezc::WideToUTF8(buffer.Str(), std::cout);
if( log_stdout )
std::cout << buffer.str() << std::endl;
if( log_file.empty() )
return;
if( !log_file_open || !file )
{
file.close();
file.clear();
std::ofstream file;
OpenFile();
do
{
file.open( log_file.c_str(), std::ios_base::out | std::ios_base::app );
if( !file )
return;
}
// if( !file )
// sleep(1);
}
while( --attempt > 0 && !file );
if( !file )
return;
file << buffer.str() << std::endl;
Ezc::WideToUTF8(buffer.Str(), file);
file.flush();
}

View File

@@ -1,59 +1,107 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilelog
#define headerfilelog
#ifndef headerfile_winix_core_log
#define headerfile_winix_core_log
#include <sstream>
#include <fstream>
#include <iostream>
#include <string>
#include "textstream.h"
enum Manipulators { logend, log1, log2, log3 };
// log1 - the first level
// log2
// log3
// log4 - the last level (debug level)
// logend - the end of a line
// logendrequest - end of a current request
// logsave - current log buffer is saved and cleared
enum Manipulators { log1, log2, log3, log4, logend, logendrequest, logsave };
class Log
{
std::ostringstream buffer;
int log_level, current_level;
std::string log_file;
bool log_stdout;
public:
Log();
void Init(int log_l, const std::string & log_f, bool log_std);
~Log();
void Init(int log_level_, bool save_each_line_, const std::string & log_file_, bool log_std, int log_max_requests);
void PutDate(Manipulators m);
Log & operator<<(const void * s);
Log & operator<<(const char * s);
Log & operator<<(const std::string * s);
Log & operator<<(const std::string & s);
Log & operator<<(const wchar_t * s);
Log & operator<<(const std::wstring * s);
Log & operator<<(const std::wstring & s);
Log & operator<<(int s);
Log & operator<<(long s);
//Log & operator<<(void * s); // ??
Log & operator<<(char s);
Log & operator<<(size_t s);
Log & operator<<(double s);
Log & operator<<(Manipulators m);
void SystemErr(int err);
void SaveLog();
void SaveLogAndClear();
private:
// buffer for the log
TextStream<std::wstring> buffer;
// log lovel from the config file
int log_level;
// current level set by a modifier (e.g. log << log3)
int current_level;
// current request for logging
// starts from zero and incremented after logendrequest modifier
int request;
// how many request to save at once
int max_requests;
// file log
std::string log_file;
std::ofstream file;
// logging to stdout
bool log_stdout;
// how many lines there are in the buffer
int lines;
// is the config file already open
bool log_file_open;
// how many lines can be in the config buffer
// default: 5000
int max_lines;
// whether to save each line (for debug)
bool save_each_line;
void OpenFile();
};
extern Log log;
extern Log nlog;

View File

@@ -1,73 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#include <cstdlib>
#include <ctime>
#include <signal.h>
#include <iostream>
#include "requestcontroller.h"
#include "data.h"
#include "log.h"
#include "request.h"
#include "db.h"
// singletons
// first 'data' then 'log' then 'request'
Data data;
Log log;
Request request;
Db db;
void signal_term(int)
{
log << log1 << "system aborted" << logend;
exit(0);
}
int main()
{
std::srand(std::time(0));
log.Init(data.log_level, data.log_file, data.log_stdout);
RequestController req_controller;
//data.read_from_file();
db.Init(data.db_database, data.db_user, data.db_pass);
if( !req_controller.Init() )
return 1;
log << log1 << "system started" << logend;
signal(SIGTERM, signal_term);
log << log1 << "checking for table consistency...";
db.CheckAllUrlSubject();
log << log1 << "done" << logend;
req_controller.Loop();
log << log1 << "system stopped" << logend;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,33 +1,430 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilemisc
#define headerfilemisc
#ifndef headerfile_winix_core_misc
#define headerfile_winix_core_misc
#include <string>
#include <sstream>
#include "log.h"
#include <ctime>
#include <cstdio>
#include "item.h"
#define MAJOR_VER 0
#define MINOR_VER 1
#define REVISION_VER 0
void ToString(std::string & s, int value);
void ToString(std::string & s, long value);
void SetUrlSubjectFromSubject(Item & item);
int ChangeLocalChar(unsigned char c);
void HtmlSpecial(std::ostringstream & out, const std::string & in);
std::string HtmlSpecial(const std::string & in);
/*
conversions between text and numbers
*/
int Toi(const std::string & str, int base = 10);
int Toi(const std::wstring & str, int base = 10);
int Toi(const char * str, int base = 10);
int Toi(const wchar_t * str, int base = 10);
long Tol(const std::string & str, int base = 10);
long Tol(const std::wstring & str, int base = 10);
long Tol(const char * str, int base = 10);
long Tol(const wchar_t * str, int base = 10);
// if the buffer is too small it will be terminated at the beginning (empty string)
// and the function returns false
template<class CharType>
bool Toa(unsigned long value, CharType * buffer, size_t buf_len, int base = 10)
{
size_t i1, i2;
long rest;
if( buf_len == 0 )
return false;
i1 = i2 = 0;
if( base < 2 ) base = 2;
if( base > 16 ) base = 16;
do
{
rest = value % base;
value = value / base;
buffer[i2++] = (rest < 10) ? char(rest) + '0' : char(rest) - 10 + 'A';
}
while(value != 0 && i2 < buf_len);
if( i2 >= buf_len )
{
buffer[0] = 0; // ops, the buffer was too small
return false;
}
buffer[i2--] = 0;
for( ; i1 < i2 ; ++i1, --i2)
{
CharType temp = buffer[i1];
buffer[i1] = buffer[i2];
buffer[i2] = temp;
}
return true;
}
// if the buffer is too small it will be terminated at the beginning (empty string)
// and the function returns false
template<class CharType>
bool Toa(long value, CharType * buffer, size_t buf_len, int base = 10)
{
if( buf_len == 0 )
return false;
CharType * buf = buffer;
if( value < 0 )
{
buffer[0] = '-';
buf += 1;
buf_len -= 1;
value = -value;
}
bool res = Toa(static_cast<unsigned long>(value), buf, buf_len, base);
if( !res )
buffer[0] = 0;
return res;
}
template<class CharType>
bool Toa(unsigned int value, CharType * buffer, size_t buf_len, int base = 10)
{
return Toa(static_cast<unsigned long>(value), buffer, buf_len, base);
}
template<class CharType>
bool Toa(int value, CharType * buffer, size_t buf_len, int base = 10)
{
return Toa(static_cast<long>(value), buffer, buf_len, base);
}
// warning: it uses its own static buffer
// one buffer for both these functions
const wchar_t * Toa(unsigned int value, int base = 10);
const wchar_t * Toa(unsigned long value, int base = 10);
const wchar_t * Toa(int value, int base = 10);
const wchar_t * Toa(long value, int base = 10);
void Toa(int value, std::string & res, int base = 10, bool clear = true);
void Toa(long value, std::string & res, int base = 10, bool clear = true);
void Toa(int value, std::wstring & res, int base = 10, bool clear = true);
void Toa(long value, std::wstring & res, int base = 10, bool clear = true);
/*
conversions between ascii text and wide characters
(destination is always std::string or std::wstring)
characters are copied as they are without any locales checking
*/
void AssignString(const char * src, size_t len, std::wstring & dst, bool clear = true);
void AssignString(const char * src, std::wstring & dst, bool clear = true);
void AssignString(const std::string & src, std::wstring & dst, bool clear = true);
void AssignString(const wchar_t * src, size_t len, std::string & dst, bool clear = true);
void AssignString(const wchar_t * src, std::string & dst, bool clear = true);
void AssignString(const std::wstring & src, std::string & dst, bool clear = true);
void AssignString(const char * src, size_t len, std::string & dst, bool clear = true);
void AssignString(const char * src, std::string & dst, bool clear = true);
void AssignString(const std::string & src, std::string & dst, bool clear = true);
void AssignString(const wchar_t * src, size_t len, std::wstring & dst, bool clear = true);
void AssignString(const wchar_t * src, std::wstring & dst, bool clear = true);
void AssignString(const std::wstring & src, std::wstring & dst, bool clear = true);
bool CorrectUrlChar(wchar_t c);
void CorrectUrlDots(std::wstring & url);
void CorrectUrlChars(std::wstring & url);
void CorrectUrlOnlyAllowedChar(std::wstring & url);
const wchar_t * DateToStr(int year, int month, int day);
const wchar_t * DateToStr(int year, int month, int day, int hour, int min, int sec);
const wchar_t * DateToStr(const tm * ptm);
const wchar_t * DateToStr(const tm & rtm);
const wchar_t * DateToStr(time_t t);
const wchar_t * DateToStrWithoutHours(const tm * ptm);
const wchar_t * DateToStrWithoutHours(const tm & rtm);
const wchar_t * DateToStrWithoutHours(time_t t);
const char * DateToStrCookie(int year, int month, int day, int hour, int min, int sec);
const char * DateToStrCookie(const tm * ptm);
const char * DateToStrCookie(const tm & rtm);
const char * DateToStrCookie(time_t t);
const wchar_t * IpToStr(unsigned int ip_);
bool IsWhite(wchar_t s);
template<class StringType>
void TrimWhite(StringType & s)
{
typename StringType::size_type i;
if( s.empty() )
return;
// looking for white characters at the end
for(i=s.size()-1 ; i>0 && IsWhite(s[i]) ; --i);
if( i==0 && IsWhite(s[i]) )
{
// the whole string has white characters
s.clear();
return;
}
// deleting white characters at the end
if( i != s.size() - 1 )
s.erase(i+1, StringType::npos);
// looking for white characters at the beginning
for(i=0 ; i<s.size() && IsWhite(s[i]) ; ++i);
// deleting white characters at the beginning
if( i != 0 )
s.erase(0, i);
}
template<class StringType>
void Trim(StringType & s, wchar_t c)
{
typename StringType::size_type i;
if( s.empty() )
return;
// looking for the 'c' characters at the end
for(i=s.size()-1 ; i>0 && s[i]==c ; --i);
if( i==0 && s[i]==c )
{
// the whole string has the 'c' characters
s.clear();
return;
}
// deleting 'c' characters at the end
if( i != s.size() - 1 )
s.erase(i+1, StringType::npos);
// looking for the 'c' characters at the beginning
for(i=0 ; i<s.size() && s[i]==c ; ++i);
// deleting the 'c' characters at the beginning
if( i != 0 )
s.erase(0, i);
}
wchar_t ToSmall(wchar_t c);
void ToSmall(std::wstring & s);
const char * SkipWhite(const char * s);
const wchar_t * SkipWhite(const wchar_t * s);
template<class StringType1, class StringType2>
bool IsSubString(const StringType1 * short_str, const StringType2 * long_str)
{
while( *short_str && *long_str && wchar_t(*short_str) == wchar_t(*long_str) )
{
++short_str;
++long_str;
}
if( *short_str == 0 )
return true;
return false;
}
template<class StringType1, class StringType2>
bool IsSubString(const StringType1 & short_str, const StringType2 & long_str)
{
return IsSubString(short_str.c_str(), long_str.c_str());
}
template<class StringType1, class StringType2>
bool IsSubStringNoCase(const StringType1 * short_str, const StringType2 * long_str)
{
while( *short_str && *long_str && ToSmall(*short_str) == ToSmall(*long_str) )
{
++short_str;
++long_str;
}
if( *short_str == 0 )
return true;
return false;
}
template<class StringType1, class StringType2>
bool IsSubStringNoCase(const StringType1 & short_str, const StringType2 & long_str)
{
return IsSubStringNoCase(short_str.c_str(), long_str.c_str());
}
template<class StringType1, class StringType2>
bool Equal(const StringType1 * str1, const StringType2 * str2)
{
while( *str1 && *str2 && wchar_t(*str1) == wchar_t(*str2) )
{
++str1;
++str2;
}
if( *str1 == 0 && *str2 == 0 )
return true;
return false;
}
template<class StringType1, class StringType2>
bool Equal(const StringType1 & str1, const StringType2 & str2)
{
return Equal(str1.c_str(), str2.c_str());
}
template<class StringType1, class StringType2>
bool EqualNoCase(const StringType1 * str1, const StringType2 * str2)
{
while( *str1 && *str2 && ToSmall(*str1) == ToSmall(*str2) )
{
++str1;
++str2;
}
if( *str1 == 0 && *str2 == 0 )
return true;
return false;
}
template<class StringType1, class StringType2>
bool EqualNoCase(const StringType1 & str1, const StringType2 & str2)
{
return EqualNoCase(str1.c_str(), str2.c_str());
}
template<class StringType>
void NoLastSlash(StringType & s)
{
if( s.empty() )
return;
size_t i = s.size();
for( ; i>0 && s[i-1]=='/' ; --i);
if( i < s.size() )
s.erase(i);
}
template<class StringType>
void NoFirstHttp(StringType & s)
{
if( s.empty() )
return;
const char http[] = "http://";
const char https[] = "https://";
if( IsSubStringNoCase(http, s.c_str()) )
{
s.erase(0, sizeof(http)/sizeof(char));
}
else
if( IsSubStringNoCase(https, s.c_str()) )
{
s.erase(0, sizeof(https)/sizeof(char));
}
}
bool ValidateEmail(const std::wstring & email);
bool IsFile(const wchar_t * file);
bool IsFile(const std::wstring & file);
bool CreateDir(const wchar_t * dir, int priv);
bool CreateDir(const std::wstring & dir, int priv);
// creating directories (dirs) under base_dir (base_dir must exist)
// if skip_last == true then last part from dir is treated as a file (the last directory is not created)
bool CreateDirs(const wchar_t * base_dir, const wchar_t * dirs, int priv = 0755, bool skip_last = false);
bool CreateDirs(const std::wstring & base_dir, const std::wstring & dirs, int priv = 0755, bool skip_last = false);
bool CopyFile(FILE * in, FILE * out);
bool CopyFile(const wchar_t * src, const wchar_t * dst);
bool CopyFile(const std::wstring & src, const std::wstring & dst);
bool RemoveFile(const wchar_t * file);
bool RemoveFile(const std::wstring & file);
bool RenameFile(const wchar_t * from, const wchar_t * to);
bool RenameFile(const std::wstring & from, const std::wstring & to);
const wchar_t * GetFileExt(const wchar_t * name);
int SelectFileType(const wchar_t * file_name);
int SelectFileType(const std::wstring & file_name);
time_t Time(const tm & par);
time_t Time(const tm * par);
tm Time(time_t par);
void UrlEncode(const std::string & in, std::string & out, bool clear_out = true);
void UrlEncode(const std::wstring & in, std::string & out, bool clear_out = true);
#endif

111
core/mount.cpp Executable file
View File

@@ -0,0 +1,111 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2009-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "mount.h"
#include "misc.h"
Mount::Mount()
{
dir_id = -1;
type = -1;
fs = -1;
}
void Mount::ClearParams()
{
size_t i;
for(i=0 ; i<param.size() ; ++i)
param[i].Clear();
}
bool Mount::IsPar(int code)
{
if( code < 0 || code >= (int)param.size() )
return false;
if( !param[code].defined )
return false;
return true;
}
bool Mount::IsArg(int code, const wchar_t * arg)
{
ParamRow::ParamArg::iterator i;
if( code < 0 || code >= (int)param.size() )
return false;
if( !param[code].defined )
return false;
for(i=param[code].arg.begin() ; i!=param[code].arg.end() ; ++i)
{
if( *i == arg )
return true;
}
return false;
}
bool Mount::IsArg(int code, const std::wstring & arg)
{
return IsArg(code, arg.c_str());
}
bool Mount::IsArg(int code, int arg)
{
ParamRow::ParamArg::iterator i;
if( code < 0 || code >= (int)param.size() )
return false;
if( !param[code].defined )
return false;
for(i=param[code].arg.begin() ; i!=param[code].arg.end() ; ++i)
{
if( Toi(*i) == arg )
return true;
}
return false;
}
const std::wstring & Mount::Arg(int code, int arg) const
{
if( code < 0 || code >= (int)param.size() )
return empty_str;
if( !param[code].defined )
return empty_str;
if( arg >= (int)param[code].arg.size() )
return empty_str;
return param[code].arg[arg];
}
const std::wstring & Mount::FirstArg(int code) const
{
return Arg(code, 0);
}

71
core/mount.h Executable file
View File

@@ -0,0 +1,71 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2009-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_mount
#define headerfile_winix_core_mount
#include <map>
#include <string>
#include <vector>
class Mount
{
public:
struct ParamRow
{
typedef std::vector<std::wstring> ParamArg;
bool defined;
ParamArg arg;
ParamRow() { defined = false; }
void Clear() { defined = false; arg.clear(); }
};
typedef std::vector<ParamRow> Param;
long dir_id;
int type;
int fs;
Param param;
Mount();
void ClearParams();
bool IsPar(int code);
bool IsArg(int code, const wchar_t * arg);
bool IsArg(int code, const std::wstring & arg);
bool IsArg(int code, int arg);
// returning the arg argument if defined (or an empty string)
const std::wstring & Arg(int code, int arg) const;
// returning the first argument (arg=0) if defined (or an empty string)
const std::wstring & FirstArg(int code) const;
private:
// for Arg() methods when the argument is not defined
const std::wstring empty_str;
};
#endif

412
core/mountparser.cpp Executable file
View File

@@ -0,0 +1,412 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "mountparser.h"
#include "log.h"
#include "misc.h"
MountParser::MountParser()
{
dirs = 0;
mount_type_tab = 0;
mount_fs_tab = 0;
mount_par_tab = 0;
}
void MountParser::SetDirs(Dirs * pdirs)
{
dirs = pdirs;
}
void MountParser::SetMountTypeTab(const std::vector<std::wstring> & tab)
{
mount_type_tab = &tab;
}
void MountParser::SetMountFsTab(const std::vector<std::wstring> & tab)
{
mount_fs_tab = &tab;
}
void MountParser::SetMountParTab(const std::vector<std::wstring> & tab)
{
mount_par_tab = &tab;
}
bool MountParser::IsWhite(int c)
{
if( c==' ' || c=='\t' || c==13 || c==160 )
return true;
return false;
}
void MountParser::SkipWhite()
{
while( IsWhite(*pinput) )
++pinput;
}
void MountParser::SkipLine()
{
while( *pinput && *pinput != 10 )
++pinput;
if( *pinput == 10 )
++pinput;
}
void MountParser::ReadWordQuote(std::wstring & res)
{
++pinput;
while( *pinput && *pinput!=10 && *pinput!='\"' )
{
if( pinput[0]=='\\' && pinput[1]=='\"' )
{
res += '\"';
pinput += 2;
}
else
if( pinput[0]=='\\' && pinput[1]=='\\' )
{
res += '\\';
pinput += 2;
}
else
{
res += *pinput;
pinput += 1;
}
}
if( *pinput == '"' )
++pinput;
}
// a white character is the separator
void MountParser::ReadWordWhite(std::wstring & res)
{
while( *pinput && *pinput!=10 && !IsWhite(*pinput) )
{
res += *pinput;
++pinput;
}
}
// the comma or the second bracket ')' are the separators
void MountParser::ReadWordComma(std::wstring & res)
{
while( *pinput && *pinput!=10 && *pinput!=',' && *pinput!=')' )
{
res += *pinput;
++pinput;
}
// trimming last white characters
// (white characters can be in the middle of the string)
TrimWhite(res);
}
void MountParser::ReadWord(std::wstring & res, bool comma_bracket_separator)
{
res.clear();
SkipWhite();
if( *pinput == '"' )
{
ReadWordQuote(res);
}
else
if( comma_bracket_separator )
{
ReadWordComma(res);
}
else
{
ReadWordWhite(res);
}
}
void MountParser::ReadParamArgsLoop(Mount::ParamRow::ParamArg & args)
{
SkipWhite();
while( *pinput && *pinput!=10 && *pinput!=')' )
{
ReadWord(temp_arg, true);
if( !temp_arg.empty() )
args.push_back(temp_arg);
if( *pinput == ',' )
++pinput;
}
}
void MountParser::ReadParamArgs(Mount::ParamRow::ParamArg & args)
{
SkipWhite();
args.clear();
if( *pinput == '(' )
{
++pinput;
ReadParamArgsLoop(args);
if( *pinput != ')' )
{
// there should be ')' at the end
// temporarily we do nothing
}
else
{
++pinput;
}
}
}
void MountParser::ReadParamName(std::wstring & res)
{
SkipWhite();
res.clear();
while( *pinput && *pinput!=10 && *pinput!=',' && *pinput!='(' && !IsWhite(*pinput) )
{
res += *pinput;
++pinput;
}
}
void MountParser::ReadParam(std::wstring & res, Mount::ParamRow::ParamArg & args)
{
ReadParamName(res);
if( res.empty() )
return;
ReadParamArgs(args);
SkipWhite();
if( *pinput == ',' )
++pinput;
}
int MountParser::FindIndex(const std::vector<std::wstring> * tab, const std::wstring & value)
{
for(size_t i=0 ; i < tab->size() ; ++i)
{
if( (*tab)[i] == value )
return static_cast<int>(i);
}
return -1;
}
void MountParser::ReadMountType()
{
ReadWord(temp);
if( temp.empty() )
{
// an empty line (some white characters only)
err = WINIX_ERR_EMPTY;
return;
}
mount.type = FindIndex(mount_type_tab, temp);
if( mount.type != -1 )
{
log << log3 << "MP: mount type: " << (*mount_type_tab)[mount.type] << logend;
}
else
{
err = WINIX_ERR_MOUNT_UNKNOWN;
log << log1 << "MP: unknown mount type: " << temp << logend;
}
}
void MountParser::ReadMountPoint()
{
ReadWord(temp);
pdir = dirs->GetDir(temp);
if( pdir )
{
mount.dir_id = pdir->id;
log << log3 << "MP: mount point (directory): " << temp << logend;
}
else
{
err = WINIX_ERR_NO_MOUNTPOINT;
log << log1 << "MP: there is no such a mount point (directory): " << temp << logend;
}
}
void MountParser::ReadFs()
{
ReadWord(temp);
mount.fs = FindIndex(mount_fs_tab, temp);
if( mount.fs != -1 )
{
log << log2 << "MP: file system: " << (*mount_fs_tab)[mount.fs] << logend;
}
else
{
err = WINIX_ERR_UNKNOWN_FILESYSTEM;
log << log1 << "MP: unknown filesystem: " << temp << logend;
}
}
void MountParser::LogMountParams()
{
size_t i;
log << log3 << "MP: mount param: " << temp << "(";
for(i=0 ; i<param_args.size() ; ++i)
{
log << param_args[i];
if( i != param_args.size()-1 )
log << ",";
}
log << ")" << logend;
}
void MountParser::ReadMountParams()
{
mount.ClearParams();
for( ReadParam(temp, param_args) ; !temp.empty() ; ReadParam(temp, param_args) )
{
int code = FindIndex(mount_par_tab, temp);
if( code != -1 )
{
mount.param[code].defined = true;
mount.param[code].arg = param_args;
LogMountParams();
}
else
{
log << log1 << "MP: unknown mount param: " << temp << " (skipped)" << logend;
}
}
}
void MountParser::ReadRow(std::map<long, Mount> & output)
{
ReadMountType();
if( err == WINIX_ERR_EMPTY )
{
err = WINIX_ERR_OK;
SkipLine();
return;
}
if( err == WINIX_ERR_OK )
ReadMountPoint();
if( err == WINIX_ERR_OK )
ReadFs();
if( err == WINIX_ERR_OK )
ReadMountParams();
if( err == WINIX_ERR_OK )
{
std::pair<std::map<long, Mount>::iterator, bool> res = output.insert( std::make_pair(mount.dir_id, mount) );
if( !res.second )
log << log1 << "MP: this mount point exists (skipped)" << logend;
}
SkipLine();
}
Error MountParser::Parse(const std::wstring & input, std::map<long, Mount> & output)
{
if( !dirs || !mount_type_tab || !mount_fs_tab || !mount_par_tab )
{
log << log1 << "pdir: " << pdir << logend;
log << log1 << "type: " << mount_type_tab << logend;
log << log1 << "fs: " << mount_fs_tab << logend;
log << log1 << "par: " << mount_par_tab << logend;
log << log1 << "MP: input tables not set" << logend;
return WINIX_NOTHING_TO_DO; // !! may a better code?
}
pinput = input.c_str();
err = WINIX_ERR_OK;
mount.param.resize(mount_par_tab->size());
mount.ClearParams();
output.clear();
while( *pinput && err == WINIX_ERR_OK )
ReadRow(output);
return err;
}

77
core/mountparser.h Executable file
View File

@@ -0,0 +1,77 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_mountparser
#define headerfile_winix_core_mountparser
#include <map>
#include <string>
#include <vector>
#include <stdlib.h>
#include <limits.h>
#include "mount.h"
#include "item.h"
#include "error.h"
#include "dirs.h"
class MountParser
{
public:
MountParser();
Error Parse(const std::wstring & input, std::map<long, Mount> & output);
void SetDirs(Dirs * pdirs);
void SetMountTypeTab(const std::vector<std::wstring> & tab);
void SetMountFsTab(const std::vector<std::wstring> & tab);
void SetMountParTab(const std::vector<std::wstring> & tab);
private:
Dirs * dirs;
const std::vector<std::wstring> * mount_type_tab;
const std::vector<std::wstring> * mount_fs_tab;
const std::vector<std::wstring> * mount_par_tab;
bool IsWhite(int c);
void SkipWhite();
void SkipLine();
void ReadWordQuote(std::wstring & res);
void ReadWordWhite(std::wstring & res);
void ReadWordComma(std::wstring & res);
void ReadWord(std::wstring & res, bool comma_bracket_separator = false);
void ReadParamArgsLoop(Mount::ParamRow::ParamArg & args);
void ReadParamArgs(Mount::ParamRow::ParamArg & args);
void ReadParamName(std::wstring & res);
void ReadParam(std::wstring & res, Mount::ParamRow::ParamArg & args);
int FindIndex(const std::vector<std::wstring> * tab, const std::wstring & value);
void ReadMountType();
void ReadMountPoint();
void ReadFs();
void LogMountParams();
void ReadMountParams();
void ReadRow(std::map<long, Mount> & output);
const wchar_t * pinput;
std::wstring temp;
std::wstring temp_arg;
Mount::ParamRow::ParamArg param_args;
Mount mount;
Item * pdir;
Error err;
};
#endif

305
core/mounts.cpp Executable file
View File

@@ -0,0 +1,305 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2009-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "mounts.h"
#include "request.h"
#include "log.h"
#include "db/db.h"
#include "plugin.h"
Mounts::Mounts()
{
pmount = &empty_mount;
}
void Mounts::CreateMountType()
{
mount_type_cms = AddMountType(L"cms");
}
void Mounts::CreateMountFs()
{
mount_fs_simplefs = AddMountFs(L"simplefs");
mount_fs_hashfs = AddMountFs(L"hashfs");
}
void Mounts::CreateMountPar()
{
mount_par_page = AddMountPar(L"page");
//mount_par_thread = AddMountPar(L"thread");
//mount_par_createthread_on = AddMountPar(L"createthread_on");
mount_par_only_root_remove = AddMountPar(L"only_root_remove");
mount_par_emacs_on = AddMountPar(L"emacs_on");
mount_par_mkdir_on = AddMountPar(L"mkdir_on");
mount_par_app = AddMountPar(L"app");
mount_par_html_template = AddMountPar(L"html_template");
}
void Mounts::CreateMounts()
{
CreateMountType();
CreateMountFs();
CreateMountPar();
plugin.Call(WINIX_ADD_MOUNTS);
empty_mount.param.resize(mount_par_tab.size());
empty_mount.ClearParams();
}
void Mounts::SetDirs(Dirs * pdirs)
{
dirs = pdirs;
}
void Mounts::SetDb(Db * pdb)
{
db = pdb;
}
void Mounts::SetCur(Cur * pcur)
{
cur = pcur;
}
int Mounts::AddMountType(const wchar_t * type)
{
mount_type_tab.push_back(type);
return static_cast<int>(mount_type_tab.size()) - 1;
}
int Mounts::AddMountType(const std::wstring & type)
{
return AddMountType(type.c_str());
}
int Mounts::AddMountFs(const wchar_t * fs)
{
mount_fs_tab.push_back(fs);
return static_cast<int>(mount_fs_tab.size()) - 1;
}
const std::wstring & Mounts::GetMountType(int id)
{
if( id < 0 || id >= (int)mount_type_tab.size() )
return empty_str;
return mount_type_tab[id];
}
int Mounts::FindMountType(const std::wstring & type)
{
for(size_t i=0 ; i<mount_type_tab.size() ; ++i)
if( mount_type_tab[i] == type )
return (int)i;
return -1;
}
int Mounts::AddMountFs(const std::wstring & fs)
{
return AddMountFs(fs.c_str());
}
const std::wstring & Mounts::GetMountFs(int id)
{
if( id < 0 || id >= (int)mount_fs_tab.size() )
return empty_str;
return mount_fs_tab[id];
}
int Mounts::AddMountPar(const wchar_t * par)
{
mount_par_tab.push_back(par);
return static_cast<int>(mount_par_tab.size()) - 1;
}
int Mounts::AddMountPar(const std::wstring & par)
{
return AddMountPar(par.c_str());
}
const std::wstring & Mounts::GetMountPar(int id)
{
if( id < 0 || id >= (int)mount_par_tab.size() )
return empty_str;
return mount_par_tab[id];
}
// reading from 'mounts'
Error Mounts::ReadMounts(const std::wstring & mounts)
{
mount_parser.SetDirs(dirs);
mount_parser.SetMountTypeTab(mount_type_tab);
mount_parser.SetMountFsTab(mount_fs_tab);
mount_parser.SetMountParTab(mount_par_tab);
Error err = mount_parser.Parse(mounts, mount_tab);
if( err != WINIX_ERR_OK )
{
log << log1 << "M: some problems with mountpoints (mountpoints table will be empty)" << logend;
mount_tab.clear();
}
CalcCurMount();
plugin.Call(WINIX_FSTAB_CHANGED);
return err;
}
// reading from /etc/fstab
Error Mounts::ReadMounts()
{
static std::wstring file = L"fstab";
Item * etc = dirs->GetEtcDir();
if( !etc )
{
log << log1 << "M: there is no /etc directory" << logend;
return WINIX_ERR_NO_ITEM;
}
Item fstab;
Error err = db->GetItem(etc->id, file, fstab);
if( err == WINIX_ERR_NO_ITEM )
{
log << log1 << "M: there is no /etc/fstab file" << logend;
return err;
}
if( err != WINIX_ERR_OK )
{
log << log1 << "M: cannot read /etc/fstab" << logend;
return err;
}
return ReadMounts(fstab.content);
}
void Mounts::MountCmsForRoot()
{
Mount mount;
mount.type = MountTypeCms();
mount.fs = MountFsSimplefs();
Item * proot = dirs->GetRootDir();
if( proot )
mount.dir_id = proot->id;
else
{
mount.dir_id = -1;
log << log1 << "M: there is no a root dir" << logend;
}
mount.param.resize(mount_par_tab.size());
mount.ClearParams();
std::pair<MountTab::iterator, bool> res = mount_tab.insert( std::make_pair(mount.dir_id, mount) );
pmount = &(res.first->second);
}
void Mounts::CalcCurMount()
{
std::vector<Item*>::reverse_iterator i;
pmount = &empty_mount;
// when the program starts (when the dir_tab is empty()
// we don't want to call MountCmsForRoot()
if( cur->request->dir_tab.empty() )
return;
for(i = cur->request->dir_tab.rbegin() ; i!=cur->request->dir_tab.rend() ; ++i)
{
std::map<long, Mount>::iterator m = mount_tab.find( (*i)->id );
if( m != mount_tab.end() )
{
pmount = &(m->second);
log << log2 << "M: current mount point is: " << GetMountType(pmount->type)
<< ", fs: " << GetMountFs(pmount->fs) << logend;
return;
}
}
// if nothing was found
// we assume that 'cms' mount point is used
MountCmsForRoot();
log << log2 << "M: current mount point is: " << GetMountType(pmount->type) << " (default)"
<< ", fs: " << GetMountFs(pmount->fs) << logend;
}
// can return null pointer
// and we don't assume cms as a default mount point if nothing is found
Mount * Mounts::CalcMount(long dir_id)
{
while( true )
{
Item * pdir = dirs->GetDir(dir_id);
if( !pdir )
return 0;
std::map<long, Mount>::iterator m = mount_tab.find( pdir->id );
if( m != mount_tab.end() )
return &(m->second);
dir_id = pdir->parent_id;
}
}
const Mounts::MountTab * Mounts::GetMountTab()
{
return &mount_tab;
}

143
core/mounts.h Executable file
View File

@@ -0,0 +1,143 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2009-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_mounts
#define headerfile_winix_core_mounts
#include <map>
#include <string>
#include <vector>
#include "mount.h"
#include "error.h"
#include "dirs.h"
#include "db/db.h"
#include "request.h"
#include "mountparser.h"
class Mounts
{
public:
/*
mount point's types
*/
int AddMountType(const wchar_t * type);
int AddMountType(const std::wstring & type);
const std::wstring & GetMountType(int id);
// id of a specific mount type (the id is always valid)
int MountTypeCms() { return mount_type_cms; }
// return -1 if there is no such a mount type
// or index otherwhise
int FindMountType(const std::wstring & type);
/*
file systems
*/
int AddMountFs(const wchar_t * fs);
int AddMountFs(const std::wstring & fs);
const std::wstring & GetMountFs(int id);
// id of a specific file system (the id is always valid)
int MountFsSimplefs() { return mount_fs_simplefs; }
int MountFsHashfs() { return mount_fs_hashfs; }
/*
mount point's parameters
*/
int AddMountPar(const wchar_t * par);
int AddMountPar(const std::wstring & par);
const std::wstring & GetMountPar(int id);
int MountParPage() { return mount_par_page; }
//int MountParThread() { return mount_par_thread; }
//int MountParCreatethreadOn() { return mount_par_createthread_on; }
int MountParOnlyRootRemove() { return mount_par_only_root_remove; }
int MountParEmacsOn() { return mount_par_emacs_on; }
int MountParMkdirOn() { return mount_par_mkdir_on; }
int MountParApp() { return mount_par_app; }
int MountParHtmlTemplate() { return mount_par_html_template; }
void SetDirs(Dirs * pdirs);
void SetDb(Db * pdb);
void SetCur(Cur * pcur);
// dir_id, mount_point
typedef std::map<long, Mount> MountTab;
Mounts();
void CreateMounts();
Error ReadMounts(const std::wstring & mounts);
Error ReadMounts();
void CalcCurMount();
Mount * CalcMount(long dir_id);
// current mount point
// will not be null after calling CalcCurMount() or ReadMounts([...])
Mount * pmount;
const MountTab * GetMountTab();
private:
Db * db;
Dirs * dirs;
Cur * cur;
Mount empty_mount;
const std::wstring empty_str;
MountParser mount_parser;
std::vector<std::wstring> mount_type_tab;
int mount_type_cms;
// simplefs
// hashfs
std::vector<std::wstring> mount_fs_tab;
int mount_fs_simplefs;
int mount_fs_hashfs;
std::vector<std::wstring> mount_par_tab;
int mount_par_page;
//int mount_par_thread;
//int mount_par_createthread_on;
int mount_par_only_root_remove;
int mount_par_emacs_on;
int mount_par_mkdir_on;
int mount_par_app;
int mount_par_html_template;
MountTab mount_tab;
void CreateMountType();
void CreateMountFs();
void CreateMountPar();
void MountCmsForRoot();
};
#endif

421
core/plugin.cpp Executable file
View File

@@ -0,0 +1,421 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include <dlfcn.h>
#include <string.h>
#include "plugin.h"
#include "pluginmsg.h"
#include "misc.h"
void Plugin::UnloadPlugins()
{
size_t i;
slots.clear();
for(i=0 ; i<plugins.size() ; ++i)
dlclose(plugins[i].handle);
plugins.clear();
}
Plugin::Plugin()
{
current_plugin = -1;
db = 0;
config = 0;
cur = 0;
system = 0;
functions = 0;
templates = 0;
synchro = 0;
session_manager = 0;
ret_false = 0;
ret_true = 0;
}
Plugin::~Plugin()
{
UnloadPlugins();
}
void Plugin::SetDb(Db * pdb)
{
db = pdb;
}
void Plugin::SetConfig(Config * pconfig)
{
config = pconfig;
}
void Plugin::SetCur(Cur * pcur)
{
cur = pcur;
}
void Plugin::SetSystem(System * psystem)
{
system = psystem;
}
void Plugin::SetFunctions(Functions * pfunctions)
{
functions = pfunctions;
}
void Plugin::SetTemplates(Templates * ptemplates)
{
templates = ptemplates;
}
void Plugin::SetSynchro(Synchro * psynchro)
{
synchro = psynchro;
}
void Plugin::SetSessionManager(SessionManager * psession_manager)
{
session_manager = psession_manager;
}
bool Plugin::SetPointers(PluginInfo & info)
{
// for safety we call a plugin function only when all our pointers are not null
bool res = (db && config && cur && system && functions && templates && synchro && session_manager);
if( !res )
log << log1 << "Plugin: cannot call a function - some of the winix pointers are null" << logend;
info.db = db;
info.config = config;
info.cur = cur;
info.system = system;
info.functions = functions;
info.templates = templates;
info.synchro = synchro;
info.session_manager = session_manager;
return res;
}
void Plugin::LoadPlugins(const std::wstring & plugins_dir, const std::vector<std::wstring> & plugins)
{
for(size_t i=0 ; i<plugins.size() ; ++i)
{
if( !plugins[i].empty() && plugins[i][0] == '/' )
{
LoadPlugin(plugins[i]);
}
else
{
temp_path = plugins_dir;
temp_path += '/';
temp_path += plugins[i];
LoadPlugin(temp_path);
}
}
}
void Plugin::LoadPlugin(const std::string & filename)
{
LoadPlugin(filename.c_str());
}
void * Plugin::LoadInitFun(const char * filename, Fun1 & fun_init)
{
void * p = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
if( !p )
{
log << log1 << "Plugin: cannot load a plugin: \"" << filename << "\"" << logend;
log << log1 << "Plugin: dlerror: " << dlerror() << logend;
return 0;
}
fun_init = (Fun1)dlfunc(p, "Init");
if( !fun_init )
{
log << log1 << "Plugin: cannot load a plugin: " << filename
<< " (there is no Init() function)" << logend;
dlclose(p);
return 0;
}
log << log2 << "Plugin: plugin loaded"
<< ", file: " << filename
<< ", index: " << plugins.size() << logend;
return p;
}
void Plugin::LoadPlugin(const char * filename)
{
Fun1 fun_init;
void * plugin_handle;
int old_current_plugin;
PluginInfo info;
if( !SetPointers(info) )
return;
if( !(plugin_handle = LoadInitFun(filename, fun_init)) )
return;
info.Clear();
old_current_plugin = current_plugin;
current_plugin = (int)plugins.size();
info.plugin_id = current_plugin;
fun_init(info);
PluginsItem item;
item.handle = plugin_handle;
item.plugin_name = reinterpret_cast<const wchar_t *>(info.p1);
plugins.push_back(item);
current_plugin = old_current_plugin;
}
void Plugin::LoadPlugin(const wchar_t * filename)
{
AssignString(filename, afilename);
LoadPlugin(afilename.c_str());
}
void Plugin::LoadPlugin(const std::wstring & filename)
{
LoadPlugin(filename.c_str());
}
bool Plugin::HasPlugin(const wchar_t * name)
{
if( *name == 0 )
return false;
for(size_t i=0 ; i<plugins.size() ; ++i)
{
if( plugins[i].plugin_name && Equal(plugins[i].plugin_name, name) )
return true;
}
return false;
}
bool Plugin::HasPlugin(const std::wstring & name)
{
return HasPlugin(name.c_str());
}
void Plugin::Call(int message, Slots::iterator & slot, PluginInfo & info)
{
if( !SetPointers(info) )
return;
current_plugin = slot->second.index;
info.plugin_id = current_plugin;
if( current_plugin != -1 )
info.plugin_data_base = cur->session->plugin_data.Get(current_plugin);
else
info.plugin_data_base = 0;
if( !slot->second.is_running )
{
if( config->log_plugin_call )
log << log1 << "Plugin: calling plugin id: " << slot->second.index << ", message: " << message << logend;
slot->second.is_running = true;
if( slot->second.fun1 )
slot->second.fun1(info);
if( slot->second.fun2 )
slot->second.fun2();
slot->second.is_running = false;
if( config->log_plugin_call )
log << log1 << "Plugin: returning from plugin id: " << slot->second.index << ", message: " << message << logend;
}
else
{
log << log1 << "Plugin: id: " << slot->second.index
<< ", message: " << message
<< ", recurrences are not allowed" << logend;
}
}
void Plugin::Call(int message, void * p1_, void * p2_, long l1_, long l2_)
{
// how many plugins return 'false' and 'true'
// we are using local variables because Call() method can be called
// from a plugin too (one Call() can execute another Call())
int ret_false_loc = 0;
int ret_true_loc = 0;
int old_current_plugin = current_plugin;
PluginInfo info;
Slots::iterator i = slots.lower_bound(message);
for( ; i!=slots.end() && i->first==message ; ++i )
{
info.Clear();
info.p1 = p1_;
info.p2 = p2_;
info.l1 = l1_;
info.l2 = l2_;
Call(message, i, info);
if( info.res )
++ret_true_loc;
else
++ret_false_loc;
}
current_plugin = old_current_plugin;
ret_false = ret_false_loc;
ret_true = ret_true_loc;
}
void Plugin::Call(int message)
{
Call(message, 0, 0, 0, 0);
}
void Plugin::Call(int message, void * p1_)
{
Call(message, p1_, 0, 0, 0);
}
void Plugin::Call(int message, void * p1_, void * p2_)
{
Call(message, p1_, p2_, 0, 0);
}
void Plugin::Call(int message, long l1_)
{
Call(message, 0, 0, l1_, 0);
}
void Plugin::Call(int message, long l1_, long l2_)
{
Call(message, 0, 0, l1_, l2_);
}
void Plugin::Call(int message, void * p1_, long l1_)
{
Call(message, p1_, 0, l1_, 0);
}
void Plugin::Call(int message, void * p1_, long l1_, long l2_)
{
Call(message, p1_, 0, l1_, l2_);
}
void Plugin::Call(int message, void * p1_, void * p2_, long l1_)
{
Call(message, p1_, p2_, l1_, 0);
}
size_t Plugin::Size()
{
return plugins.size();
}
int Plugin::True()
{
return ret_true;
}
int Plugin::False()
{
return ret_false;
}
void Plugin::Assign(int message, Fun1 fun1)
{
Slot s;
if( current_plugin == -1 )
return;
s.fun1 = fun1;
s.index = current_plugin;
slots.insert( std::make_pair(message, s) );
log << log3 << "Plugin: added function for message: " << message << ", plugin index: " << s.index << logend;
}
void Plugin::Assign(int message, Fun2 fun2)
{
Slot s;
if( current_plugin == -1 )
return;
s.fun2 = fun2;
s.index = current_plugin;
slots.insert( std::make_pair(message, s) );
log << log3 << "Plugin: added function for message: " << message << ", plugin index: " << s.index << logend;
}

219
core/plugin.h Executable file
View File

@@ -0,0 +1,219 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilecmsluplugin
#define headerfilecmsluplugin
#include <vector>
#include <string>
#include <map>
#include "pluginmsg.h"
#include "log.h"
#include "plugindata.h"
#include "config.h"
#include "request.h"
#include "system.h"
#include "sessionmanager.h"
#include "synchro.h"
#include "functions/functions.h"
#include "templates/templates.h"
/*
all your plugin functions can have signature either:
void my_function(PluginInfo & info); or
void my_function();
only the main Init should have:
extern "C" void Init(PluginFunction & info);
in the Init you can add your own functions by using plugin.Assign() method
and you can set the name of the plugin by setting info.p1 pointer
to a string buffer (const char *)
(this buffer will not be copied so it should not be destroyed after Init finishes)
also in Init you can only use logger (log) info.config and info.db objects
(the rest winix objects are not initialized yet)
*/
struct PluginInfo
{
// these variables are used for some purposes
// depending on a hook in which they are used
void * p1;
void * p2;
long l1;
long l2;
// unique plugin identifier
int plugin_id;
// objects from winix which are accessible from a plugin
Db * db;
Config * config;
Cur * cur;
System * system;
Functions * functions;
Templates * templates;
Synchro * synchro;
SessionManager * session_manager;
// pointer to the plugin session (can be null if not set by the plugin)
// you should use WINIX_SESSION_CREATED and WINIX_SESSION_REMOVE
// to create your plugin's session data
PluginDataBase * plugin_data_base; // !! zmienic nazwe na plugin_session_base ? a moze session_base; a moze plugin_session?
// function return status
// default: false (if not set by the plugin)
bool res;
void Clear()
{
// pointers to winix objects are not cleared here
p1 = 0;
p2 = 0;
l1 = 0;
l2 = 0;
plugin_id = -1;
plugin_data_base = 0;
res = false;
}
};
class Plugin
{
public:
// index of a plugin which is called by Call() method
// normally: -1
int current_plugin;
// Fun is a type of a function you should provide in your plugin
typedef void (*Fun1)(PluginInfo &);
typedef void (*Fun2)(void);
struct Slot
{
Fun1 fun1;
Fun2 fun2;
int index; // plugin index (which plugin has inserted the slot)
bool is_running;
Slot()
{
fun1 = 0;
fun2 = 0;
index = -1;
is_running = false;
}
};
Plugin();
~Plugin();
void SetDb(Db * pdb);
void SetConfig(Config * pconfig);
void SetCur(Cur * pcur);
void SetSystem(System * psystem);
void SetFunctions(Functions * pfunctions);
void SetTemplates(Templates * ptemplates);
void SetSynchro(Synchro * psynchro);
void SetSessionManager(SessionManager * psession_manager);
void LoadPlugin(const char * filename);
void LoadPlugin(const std::string & filename);
void LoadPlugin(const wchar_t * filename);
void LoadPlugin(const std::wstring & filename);
void LoadPlugins(const std::wstring & plugins_dir, const std::vector<std::wstring> & plugins);
void UnloadPlugins();
bool HasPlugin(const wchar_t * name);
bool HasPlugin(const std::wstring & name);
void Call(int message);
void Call(int message, void * p1_);
void Call(int message, void * p1_, void * p2_);
void Call(int message, long l1_);
void Call(int message, long l1_, long l2_);
void Call(int message, void * p1_, long l1_);
void Call(int message, void * p1_, long l1_, long l2_);
void Call(int message, void * p1_, void * p2_, long l1_);
void Call(int message, void * p1_, void * p2_, long l1_, long l2_);
// how many plugins there are
size_t Size();
// how many plugins returned 'true'
// from last Call()
int True();
// how many plugins returned 'false'
// from last Call()
int False();
// assign a function to a message
// you can assign more than one function to a specific message
void Assign(int message, Fun1);
void Assign(int message, Fun2);
private:
Db * db;
Config * config;
Cur * cur;
System * system;
Functions * functions;
Templates * templates;
Synchro * synchro;
SessionManager * session_manager;
int ret_false;
int ret_true;
std::wstring temp_path;
struct PluginsItem
{
void * handle;
const wchar_t * plugin_name; // plugin name (can be null if was not set by the plugin)
};
typedef std::vector<PluginsItem> Plugins;
Plugins plugins;
typedef std::multimap<int, Slot> Slots;
Slots slots;
std::string afilename;
void * LoadInitFun(const char * filename, Fun1 & fun_init);
void Call(int message, Slots::iterator & slot, PluginInfo & info);
bool SetPointers(PluginInfo & info);
};
extern Plugin plugin;
#endif

125
core/plugindata.cpp Executable file
View File

@@ -0,0 +1,125 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "plugindata.h"
#include "plugin.h"
#include "log.h"
void PluginData::Assign(size_t index, PluginDataBase * data)
{
if( index >= table.size() )
Resize(index+1);
table[index] = data;
}
void PluginData::Assign(PluginDataBase * data)
{
if( plugin.current_plugin == -1 )
{
log << log1 << "PD: Assign(PluginDataBase*) should be called only from plugins" << logend;
return;
}
Assign(plugin.current_plugin, data);
}
PluginDataBase * PluginData::Get(size_t index)
{
if( index >= table.size() )
Resize(index+1);
return table[index];
}
PluginDataBase * PluginData::Get()
{
if( plugin.current_plugin == -1 )
{
log << log1 << "PD: Get() should be called only from plugins" << logend;
return 0;
}
return Get(plugin.current_plugin);
}
void PluginData::DeleteAll()
{
if( table.empty() )
return;
plugin.Call(WINIX_SESSION_REMOVE);
for(size_t i=0 ; i<table.size() ; ++i)
table[i] = 0;
}
PluginData::PluginData()
{
}
PluginData::PluginData(const PluginData & p)
{
operator=(p);
}
PluginData & PluginData::operator=(const PluginData & p)
{
// we don't copy all pointers - only resize the table
// pointers will be set to zero
Resize(p.Size());
return *this;
}
PluginData::~PluginData()
{
DeleteAll();
}
size_t PluginData::Size() const
{
return table.size();
}
void PluginData::Resize(size_t new_size)
{
size_t old_size = table.size();
if( old_size == new_size )
return;
table.resize(new_size);
for(size_t i = old_size ; i<new_size ; ++i)
table[i] = 0;
}

56
core/plugindata.h Executable file
View File

@@ -0,0 +1,56 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_plugindata
#define headerfile_winix_core_plugindata
#include <vector>
struct PluginDataBase
{
virtual ~PluginDataBase() {}
};
class PluginData
{
public:
void Assign(size_t index, PluginDataBase * data);
void Assign(PluginDataBase * data);
PluginDataBase * Get(size_t index);
PluginDataBase * Get();
void DeleteAll();
PluginData();
PluginData(const PluginData & p);
PluginData & operator=(const PluginData & p);
~PluginData();
size_t Size() const;
void Resize(size_t new_size);
private:
std::vector<PluginDataBase*> table;
};
#endif

106
core/pluginmsg.h Executable file
View File

@@ -0,0 +1,106 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilecmslupluginmsg
#define headerfilecmslupluginmsg
// here you can add your own EZC functions ([function])
// PluginInfo.p1 is a pointer to Ezc::Functions object
#define WINIX_TEMPLATES_CREATEFUNCTIONS 999
// here you can add your own EZC functions to notify system
// warning: this functions will be called from an other thread
// so you should use synchro->Lock() and synchro->Unlock()
// when attempting to winix objects
// PluginInfo.p1 is a pointer to Ezc::Functions object
// which is defined as:
// Ezc::Functions<NotifyStream> ezc_functions;
// and Notify Stream is:
// typedef TextStream<std::wstring> NotifyStream;
#define WINIX_NOTIFY_TEMPLATES_CREATEFUNCTIONS 998
// winix function and parameters have been parsed
// the request.status is OK
// (the winix function was not called yet)
#define WINIX_PREPARE_REQUEST 2000
// post and get functions have done their jobs
// now you can act
// this is called only if the request.status is OK
#define WINIX_PROCESS_REQUEST 2001
// prepere your content for displaying
// this is called after WINIX_PROCESS_REQUEST
// and when there is not a redirect
// request.status is not checked here
#define WINIX_CONTENT_MAKE 2002
// here you can attach your own session data (based on PluginDataBase class)
// call request.session->plugin_data.Assign(pointer)
#define WINIX_SESSION_CREATED 3000
// here you should remove your session data
#define WINIX_SESSION_REMOVE 3001
// when a session is changed (you can save a pointer to your data here)
#define WINIX_SESSION_CHANGED 3002
// the winix is closing
// the is not any session available (cur->session is null)
#define WINIX_CLOSE 3004
// a file or symlink was removed (rm function)
// PluginInfo::l1 is the file (item) id
// !! moze zmienic nazwe i dodac symlink w nazwie?
#define WINIX_FILE_REMOVED 3005
// directory was removed (rm function)
// PluginInfo::l1 is the dir id
#define WINIX_DIR_REMOVED 3006
// preparing to remove a directory (rm function)
// PluginInfo::l1 is the dir id
#define WINIX_DIR_PREPARE_TO_REMOVE 3007
// winix is initialized,
// now you can initialize your plugin
#define WINIX_PLUGIN_INIT 3008
// here you can add your own mount point, file systems, mount parameters
// for adding a new mount type call: system->mounts.AddMountType("new_mount_name")
#define WINIX_ADD_MOUNTS 3009
// add plugin functions here
#define WINIX_CREATE_FUNCTIONS 3010
// choose a default function
// if you do not select it then it will be choosen by winix
#define WINIX_SELECT_DEFAULT_FUNCTION 3011
// /etc/fstab has been changed
// now we have new mount points
#define WINIX_FSTAB_CHANGED 3012
// here you add your own template to notification system
// call system->notify.AddTemplate() method
// with a template file name
#define WINIX_NOTIFY_ADD_TEMPLATE 3013
// values from 4000 - 4099 reserved for 'thread' plugin
// see plugins/thread/pluginmsg.h
// values from 4100 - 4199 reserved for 'ticket' plugin
// see plugins/ticket/pluginmsg.h
#endif

606
core/postmultiparser.cpp Executable file
View File

@@ -0,0 +1,606 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "postmultiparser.h"
#include "log.h"
#include "utf8.h"
#include "misc.h"
PostMultiParser::PostMultiParser()
{
in_buffer = new unsigned char[WINIX_POSTMULTI_INPUT_BUFFER];
}
PostMultiParser::PostMultiParser(const PostMultiParser & p)
{
in_buffer = new unsigned char[WINIX_POSTMULTI_INPUT_BUFFER];
config = p.config;
}
PostMultiParser & PostMultiParser::operator=(const PostMultiParser & p)
{
in_buffer = new unsigned char[WINIX_POSTMULTI_INPUT_BUFFER];
config = p.config;
return *this;
}
PostMultiParser::~PostMultiParser()
{
delete [] in_buffer;
}
void PostMultiParser::SetConfig(Config * pconfig)
{
config = pconfig;
}
void PostMultiParser::ReadBoundary()
{
boundary.clear();
while( last != -1 && last != 10 && last != 13 )
{
boundary += last;
ReadChar();
}
if( last == 13 )
{
ReadChar();
line_end_dos = true;
}
if( last == 10 )
ReadChar();
}
bool PostMultiParser::IsWhite(int c)
{
if( c==' ' || c=='\t' || c==13 )
return true;
return false;
}
void PostMultiParser::SkipWhite()
{
while( IsWhite(last) )
ReadChar();
}
bool PostMultiParser::IsHeader()
{
SkipWhite();
if( last == 10 )
{
ReadChar();
return false;
}
return true;
}
void PostMultiParser::ReadHeaderName()
{
SkipWhite();
while( last!=-1 && last!=':' && last!='=' && !IsWhite(last) && last!=10 )
{
header_name += last;
ReadChar();
}
SkipWhite();
if( last != ':' && last != '=' )
{
err = WINIX_ERR_BROKEN_INPUT;
return;
}
ReadChar();
}
void PostMultiParser::ReadHeaderValue()
{
bool was_apost = false;
SkipWhite();
if( last == '"' )
{
was_apost = true;
ReadChar();
}
while( last!=-1 && last!=10 &&
((!was_apost && last!=';' && !IsWhite(last)) || (was_apost && last!='"')))
{
header_value += last;
ReadChar();
}
if( was_apost )
{
if( last != '"' )
{
err = WINIX_ERR_BROKEN_INPUT;
return;
}
ReadChar();
}
SkipWhite();
if( last != ';' && last != 10 )
{
err = WINIX_ERR_BROKEN_INPUT;
return;
}
ReadChar();
}
void PostMultiParser::ReadPartHeader()
{
header_name.clear();
header_value.clear();
ReadHeaderName();
if( err != WINIX_ERR_OK )
return;
ReadHeaderValue();
if( err != WINIX_ERR_OK )
return;
log << "PMP: " << header_name << ": " << header_value << logend;
if( header_name == "name" )
name = header_value;
if( header_name == "filename" )
filename = header_value;
}
bool PostMultiParser::HasBoundary()
{
if( content.size() < boundary.size() )
return false;
size_t c = content.size() - boundary.size();
size_t b = 0;
for( ; c<content.size() ; ++c, ++b)
{
if( content[c] != boundary[b] )
return false;
}
return true;
}
void PostMultiParser::LogFirst(const std::string & to_log, size_t len)
{
size_t i;
if( len > to_log.size() )
len = to_log.size();
log << log3 << "PMP: Content (";
if( len > 0 )
log << "len: " << to_log.size() << ", first " << len << " bytes";
else
log << "empty";
log << "): \"";
for(i=0 ; i<len ; ++i)
{
if( to_log[i] < 32 )
log << '.';
else
log << to_log[i];
}
log << "\"" << logend;
}
void PostMultiParser::ReadContentSkipBoundary(bool has_boundary)
{
if( has_boundary && content.size() >= boundary.size() )
{
content.erase(content.size()-boundary.size());
content_len -= boundary.size();
}
// the last new line character doesn't belong to the content
// this is a new line character before the boundary
if( !content.empty() && content[content.size()-1] == 10 )
{
content.erase(content.size()-1);
content_len -= 1;
if( line_end_dos && !content.empty() && content[content.size()-1] == 13 )
{
content.erase(content.size()-1);
content_len -= 1;
}
}
}
void PostMultiParser::ReadContentToFileLoop()
{
bool has_boundary = false;
while( last!=-1 )
{
content += last;
content_len += 1;
ReadChar();
if( HasBoundary() )
{
has_boundary = true;
break;
}
if( content.size() >= WINIX_POSTMULTI_OUTPUT_BUFFER )
{
tmp_file.write(content.c_str(), content.size());
content.clear();
}
if( config->post_file_max != 0 && content_len > config->post_file_max )
{
err = WINIX_ERR_INPUT_TOO_LARGE;
log << log1 << "PMP: content greater than " << config->post_file_max << " (skipping)" << logend;
return;
}
}
ReadContentSkipBoundary(has_boundary);
// saving the rest
if( !content.empty() )
{
tmp_file.write(content.c_str(), content.size());
content.clear();
}
}
void PostMultiParser::ReadContentToFile()
{
time_t t1, t2;
content.clear();
content.reserve(WINIX_POSTMULTI_OUTPUT_BUFFER);
content_len = 0;
t1 = time(0);
ReadContentToFileLoop();
tmp_file.close();
log << log2 << "PMP: content size: " << content_len << " bytes" << logend;
t2 = time(0);
if( t2 - t1 > 1 )
log << log2 << "PMP: content read in " << (t2-t1) << " sec" << logend;
}
void PostMultiParser::ReadContentLoop()
{
bool has_boundary = false;
while( last!=-1 && !(has_boundary=HasBoundary()) )
{
content += last;
content_len += 1;
ReadChar();
if( config->post_file_max != 0 && content_len > (size_t)config->post_file_max )
{
err = WINIX_ERR_INPUT_TOO_LARGE;
log << log1 << "PMP: content greater than " << config->post_file_max << " (skipping)" << logend;
return;
}
}
ReadContentSkipBoundary(has_boundary);
}
void PostMultiParser::ReadContent()
{
content.clear();
content_len = 0;
ReadContentLoop();
log << log2 << "PMP: content size: " << content_len << " bytes" << logend;
LogFirst(content, 200);
}
void PostMultiParser::AddNormalPostVar()
{
if( post_tab->size() >= WINIX_POSTTABLE_MAXSIZE )
{
err = WINIX_ERR_INPUT_TOO_LARGE;
log << log1 << "PMP: more than " << WINIX_POSTTABLE_MAXSIZE << " post variables (skipping)" << logend;
return;
}
if( config->utf8 )
{
Ezc::UTF8ToWide(name, namew);
Ezc::UTF8ToWide(content, contentw);
}
else
{
AssignString(name, namew);
AssignString(content, contentw);
}
std::pair<PostTab::iterator, bool> res = post_tab->insert( std::make_pair(namew, contentw) );
bool added = res.second;
log << log2 << "PMP: POST var, name: \"" << namew << "\"";
if( !added )
log << log2 << " (skipped)";
log << logend;
}
void PostMultiParser::AddFilePostVar()
{
if( post_file_tab->size() >= WINIX_POSTTABLE_MAXSIZE )
{
err = WINIX_ERR_INPUT_TOO_LARGE;
log << log1 << "PMP: more than " << WINIX_POSTTABLE_MAXSIZE << " post file variables (skipping)" << logend;
return;
}
if( config->utf8 )
{
Ezc::UTF8ToWide(name, namew);
Ezc::UTF8ToWide(filename, post_file_temp.filename);
}
else
{
AssignString(name, namew);
AssignString(filename, post_file_temp.filename);
}
post_file_temp.tmp_filename = tmp_filename;
std::pair<PostFileTab::iterator, bool> res = post_file_tab->insert( std::make_pair(namew, post_file_temp) );
bool added = res.second;
log << log2 << "PMP: POST FILE var, name: \"" << namew << "\"";
if( !added )
log << log2 << " (skipped)";
log << logend;
}
void PostMultiParser::AddPostVar()
{
if( name.empty() )
return;
if( filename.empty() )
{
AddNormalPostVar();
}
else
{
AddFilePostVar();
}
}
void PostMultiParser::CheckBoundaryEnd()
{
if( last == '-' )
{
ReadChar();
if( last != '-' )
{
err = WINIX_ERR_BROKEN_INPUT;
return;
}
// end of parsing
// the rest input (if exists) is ignored
last = -1;
}
// skipping a new line after the boundary
if( last == 13 )
ReadChar();
if( last == 10 )
ReadChar();
}
void PostMultiParser::CreateTmpFile()
{
wchar_t buf[1024];
size_t buf_len = sizeof(buf)/sizeof(wchar_t);
if( config->upload_dir.empty() )
{
log << log1 << "PMP: upload_dir is not set in the config" << logend;
err = WINIX_ERR_CANT_CREATE_FILE;
return;
}
swprintf(buf, buf_len, L"%ls/tmp/pmp_%u_%d_%u", config->upload_dir.c_str(), (unsigned)getpid(), tmp_filename_postfix, rand());
tmp_filename_postfix += 1;
tmp_filename = buf;
Ezc::WideToUTF8(tmp_filename, atmp_filename);
tmp_file.open(atmp_filename.c_str(), std::ios_base::binary | std::ios_base::out);
// !! dodac ustawienie chmod config.upload_files_chmod dla tymczasowego pliku
if( !tmp_file )
{
log << log1 << "PMP: can't create a temporary file: " << atmp_filename << logend;
err = WINIX_ERR_CANT_CREATE_FILE;
return;
}
log << log3 << "PMP: using temporary file for the content: " << atmp_filename << logend;
}
void PostMultiParser::ReadPart()
{
name.clear();
filename.clear();
while( IsHeader() )
ReadPartHeader();
if( err != WINIX_ERR_OK )
return;
if( !filename.empty() )
CreateTmpFile();
if( err != WINIX_ERR_OK )
return;
if( !filename.empty() )
ReadContentToFile();
else
ReadContent();
if( err == WINIX_ERR_OK )
{
AddPostVar();
CheckBoundaryEnd();
}
if( err != WINIX_ERR_OK && !filename.empty() )
{
log << log1 << "PMP: deleting the tmp file: " << tmp_filename << logend;
RemoveFile(tmp_filename);
}
}
void PostMultiParser::ReadChar()
{
if( last == -1 )
return;
if( in_buffer_ind >= in_buffer_len )
{
if( in_buffer_len < WINIX_POSTMULTI_INPUT_BUFFER )
{
last = -1;
return;
}
in_buffer_len = FCGX_GetStr((char*)in_buffer, WINIX_POSTMULTI_INPUT_BUFFER, in);
in_buffer_ind = 0;
}
if( in_buffer_len == 0 )
{
last = -1;
}
else
{
last = in_buffer[in_buffer_ind];
in_buffer_ind += 1;
}
}
Error PostMultiParser::Parse(FCGX_Stream * in_, PostTab & post_tab_, PostFileTab & post_file_tab_)
{
in = in_;
last = 0;
err = WINIX_ERR_OK;
line_end_dos = false;
in_buffer_ind = WINIX_POSTMULTI_INPUT_BUFFER;
in_buffer_len = WINIX_POSTMULTI_INPUT_BUFFER;
post_tab = &post_tab_;
post_file_tab = &post_file_tab_;
tmp_filename_postfix = 1;
ReadChar();
ReadBoundary();
if( boundary.empty() )
return WINIX_ERR_NO_BOUNDARY;
while( last!=-1 && err == WINIX_ERR_OK )
ReadPart();
if( err != WINIX_ERR_OK )
{
post_tab->clear();
post_file_tab->clear();
if( err != WINIX_ERR_INPUT_TOO_LARGE && err != WINIX_ERR_CANT_CREATE_FILE )
log << log1 << "PMP: syntax error" << logend;
}
return err;
}

100
core/postmultiparser.h Executable file
View File

@@ -0,0 +1,100 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_postmultiparser
#define headerfile_winix_core_postmultiparser
#include <string>
#include <fcgiapp.h>
#include <fstream>
#include "error.h"
#include "requesttypes.h"
#include "config.h"
// 2 MB
#define WINIX_POSTMULTI_INPUT_BUFFER 2097152
#define WINIX_POSTMULTI_OUTPUT_BUFFER 2097152
class PostMultiParser
{
public:
PostMultiParser();
PostMultiParser(const PostMultiParser &);
PostMultiParser & operator=(const PostMultiParser &);
~PostMultiParser();
void SetConfig(Config * pconfig);
Error Parse(FCGX_Stream * in_, PostTab & post_tab_, PostFileTab & post_file_tab_);
private:
Config * config;
FCGX_Stream * in;
unsigned char * in_buffer;
std::ofstream tmp_file;
std::wstring tmp_filename;
std::string atmp_filename;
int tmp_filename_postfix;
size_t in_buffer_ind;
size_t in_buffer_len;
PostTab * post_tab;
PostFileTab * post_file_tab;
int last; // last read character
bool line_end_dos;
std::string boundary;
std::string content;
size_t content_len;
std::string header_name, header_value;
Error err;
std::string name, filename;
std::wstring namew, contentw;
PostFile post_file_temp;
void LogFirst(const std::string & to_log, size_t len);
bool IsWhite(int c);
void SkipWhite();
void AddNormalPostVar();
void AddFilePostVar();
void AddPostVar();
void ReadBoundary();
bool IsHeader();
void ReadHeaderName();
void ReadHeaderValue();
void ReadPartHeader();
void CreateTmpFile();
bool HasBoundary();
void ReadContentSkipBoundary(bool has_boundary);
void ReadContentToFileLoop();
void ReadContentToFile();
void ReadContentLoop();
void ReadContent();
void CheckBoundaryEnd();
void ReadPart();
void ReadChar();
};
#endif

View File

@@ -1,26 +1,30 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilepostparser
#define headerfilepostparser
#ifndef headerfile_winix_core_postparser
#define headerfile_winix_core_postparser
#include <fcgiapp.h>
#include <string>
#include "httpsimpleparser.h"
#include "requesttypes.h"
#include "misc.h"
class PostParser : public HttpSimpleParser
{
FCGX_Stream * in;
PostTable & post_table;
PostTab * post_tab;
std::wstring temp_name, temp_value;
bool input_as_utf8;
protected:
@@ -33,9 +37,20 @@ protected:
virtual void Parameter(std::string & name, std::string & value)
{
std::pair<PostTable::iterator, bool> res = post_table.insert( std::make_pair(name, value) );
if( input_as_utf8 )
{
Ezc::UTF8ToWide(name, temp_name);
Ezc::UTF8ToWide(value, temp_value);
}
else
{
AssignString(name, temp_name);
AssignString(value, temp_value);
}
std::pair<PostTab::iterator, bool> res = post_tab->insert( std::make_pair(temp_name, temp_value) );
log << log2 << "Method POST, name: \"" << name << "\", value: \"" << value << "\"";
log << log2 << "Method POST, name: \"" << temp_name << "\", value: \"" << temp_value << "\"";
if( res.second == false )
log << log2 << " (skipped)";
@@ -46,8 +61,24 @@ protected:
public:
PostParser(FCGX_Stream * in_, PostTable & post_table_) : in(in_), post_table(post_table_)
PostParser()
{
input_as_utf8 = false;
}
void UTF8(bool utf)
{
input_as_utf8 = utf;
}
void Parse(FCGX_Stream * in_, PostTab & post_tab_)
{
in = in_;
post_tab = &post_tab_;
HttpSimpleParser::Parse();
}
};

168
core/rebus.cpp Executable file
View File

@@ -0,0 +1,168 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include <cstdlib>
#include <limits.h>
#include "log.h"
#include "rebus.h"
#include "misc.h"
#include "cur.h"
void Rebus::SetCur(Cur * pcur)
{
cur = pcur;
}
bool Rebus::InitPair(int a, int b, Item & item)
{
wchar_t buffer[100];
size_t buffer_len = sizeof(buffer) / sizeof(wchar_t);
bool add = false;
if( a+b <= 15 )
{
swprintf(buffer, buffer_len, L"%d+%d", a, b);
item.question = buffer;
item.answer = a+b;
add = true;
}
if( a-b >= 0 )
{
swprintf(buffer, buffer_len, L"%d-%d", a, b);
item.question = buffer;
item.answer = a-b;
add = true;
}
return add;
}
void Rebus::Init()
{
int a, b;
Item item;
item.key = 0;
for(a=1 ; a<10 ; ++a)
{
for(b=1 ; b<10 ; ++b)
{
if( InitPair(a, b, item) )
{
table.push_back(item);
item.key += 1;
}
}
}
}
Rebus::Item * Rebus::Rand()
{
size_t len = table.size();
if( len == 0 )
// empty table, call Init() first
return 0;
size_t i = size_t( ((double)rand()*(double)len) / (double(RAND_MAX)+1.0) );
if( i >= table.size() )
{
log << log1 << "Rebus: Rand() index too big" << logend;
// oops, it should not be greater then table.size()
return &table[0];
}
return &table[0] + i;
}
bool Rebus::IsAnswerOk(Rebus::Item * item, const std::wstring & answer)
{
if( item == 0 )
return false;
wchar_t * end;
const wchar_t * a = answer.c_str();
a = SkipWhite(a);
int value = (int)wcstol(a, &end, 10);
if( a == end )
// nothing has been read
return false;
log << log2 << "Rebus: your answer is: " << value << logend;
end = (wchar_t*)SkipWhite(end);
if( *end != 0 )
{
// something is at the end
return false;
}
bool result = (item->answer == value);
if( result )
log << log3 << "Rebus: the answer is correct" << logend;
return result;
}
bool Rebus::CheckRebus()
{
if( !cur->session )
return false;
if( cur->session->puser )
// logged users don't have to use the rebus
return true;
if( cur->session->rebus_checked )
return true;
cur->session->rebus_checked = true;
if( !cur->session->rebus_item )
{
log << log1 << "Rebus: rebus not set" << logend;
return false;
}
if( IsAnswerOk(cur->session->rebus_item, cur->request->PostVar(L"rebus")) )
return true;
log << log1 << "Rebus: rebus has an incorrect answer" << logend;
// don't add cur->session->spam_score when the rebus has incorrect answer
// a user could have made a mistake
return false;
}

51
core/rebus.h Executable file
View File

@@ -0,0 +1,51 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_rebus
#define headerfile_winix_core_rebus
#include <string>
#include <vector>
struct Cur;
class Rebus
{
public:
struct Item
{
int key;
std::wstring question;
int answer;
};
void SetCur(Cur * pcur);
void Init();
Item * Rand();
bool IsAnswerOk(Item * item, const std::wstring & answer);
bool CheckRebus();
private:
Cur * cur;
bool InitPair(int a, int b, Item & item);
std::vector<Item> table;
};
#endif

View File

@@ -1,101 +1,139 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "request.h"
#include "log.h"
#include "plugin.h"
#include "misc.h"
Request::Request()
Request::Request() : char_empty(0)
{
Clear();
id = 0;
}
void Request::SetConfig(Config * pconfig)
{
config = pconfig;
}
void Request::ClearPostFileTmp()
{
// deleting temporary files (if exists)
while( !post_file_tab.empty() )
{
const std::wstring & tmp_filename = post_file_tab.begin()->second.tmp_filename;
if( RemoveFile(tmp_filename) )
log << log3 << "Request: deleted tmp file: " << tmp_filename << logend;
post_file_tab.erase(post_file_tab.begin());
}
}
void Request::Clear()
{
// warning: don't clear in, out, err, env
get_table.clear();
post_table.clear();
cookie_table.clear();
// id is never 0
if( ++id == 0 )
++id;
ClearPostFileTmp();
get_tab.clear();
post_tab.clear();
post_file_tab.clear();
cookie_tab.clear();
method = none;
headers.str("");
page.str("");
debug.str("");
env_request_method = 0;
env_request_uri = 0;
env_http_cookie = 0;
session = 0;
role = responder;
result = err404; // tutaj moze cos lepszego, cos w stylu 'not implemented'
dir = -1;
cur_dir_table.clear();
item_table.clear();
dir_table.clear();
headers.Clear();
page.Clear();
debug.Clear();
env_request_method = &char_empty;
env_request_uri = &char_empty;
env_http_cookie = &char_empty;
env_remote_addr = &char_empty;
env_http_host = &char_empty;
env_http_user_agent = &char_empty;
env_fcgi_role = &char_empty;
env_content_type = &char_empty;
env_http_accept_encoding = &char_empty;
item_tab.clear();
item.Clear();
str.clear();
}
dir_tab.clear();
last_item = &item;
is_item = false;
function = 0; // !! dodac jakas empty funkcje
param_tab.clear();
status = WINIX_ERR_OK;
void Request::CopyFirstItem()
{
if( !request.item_table.empty() )
request.item = request.item_table[0];
else
{
request.item.Clear();
log << log1 << "Request::CopyFirstItem: item_table is empty" << logend;
request.result = err_internal;
}
browser_msie = false;
redirect_to.clear();
x_sendfile.clear();
send_as_attachment = false;
}
// value can be null
void Request::SetCookie(const char * name, const char * value)
void Request::SetCookie(const char * name, const char * value, tm * expires)
{
request.headers << "Set-Cookie: " << name << "=";
headers << "Set-Cookie: " << name << "=";
if( value && value[0]!=0 )
request.headers << value;
headers << value;
else
request.headers << "\"\"";
headers << "\"\"";
request.headers << "; path=/\r\n";
if( expires )
headers << "; expires=" << DateToStrCookie(expires) << " GMT";
headers << "; path=/; domain=." << config->base_server << "\r\n";
}
void Request::SetCookie(const char * name, long value)
void Request::SetCookie(const char * name, long value, tm * expires)
{
request.headers << "Set-Cookie: " << name << "=" << value << "; path=/\r\n";
headers << "Set-Cookie: " << name << "=" << value;
if( expires )
headers << "; expires=" << DateToStrCookie(expires) << " GMT";
headers << "; path=/; domain=." << config->base_server << "\r\n";
}
bool Request::IsPostVar(const char * var)
bool Request::IsPostVar(const wchar_t * var)
{
PostTable::iterator p;
PostTab::iterator p;
p = post_table.find(var);
p = post_tab.find(var);
if( p == post_table.end() )
if( p == post_tab.end() )
return false;
return true;
@@ -103,39 +141,57 @@ return true;
std::string & Request::PostVar(const char * var)
const std::wstring & Request::PostVar(const wchar_t * var)
{
PostTable::iterator p;
PostTab::iterator p = post_tab.find(var);
p = post_table.find(var);
if( p == post_tab.end() )
return str_empty;
if( p == post_table.end() )
throw Error();
return p->second;
}
//
void Request::PrintGetTable()
bool Request::PostVar(const wchar_t * var, std::wstring & result)
{
debug << "get_table: " << get_table.size() << "\n";
PostTab::iterator p = post_tab.find(var);
for(GetTable::iterator i = get_table.begin() ; i != get_table.end() ; ++i)
debug << " \"" << *i << "\"\n";
if( p == post_tab.end() )
{
result.clear();
return false;
}
debug << std::endl;
result = p->second;
return true;
}
std::wstring * Request::PostVarp(const wchar_t * var)
{
PostTab::iterator p = post_tab.find(var);
if( p == post_tab.end() )
return 0;
return &p->second;
}
void Request::PrintGetTab()
{
debug << "get_tab: " << get_tab.size() << "\n";
for(GetTab::iterator i = get_tab.begin() ; i != get_tab.end() ; ++i)
debug << " \"" << *i << "\"\n";
debug << '\n';
}
/*
void Request::PrintEnv()
{
char ** e;
@@ -145,230 +201,67 @@ char ** e;
for( e = env ; *e ; ++e )
debug << ' ' << *e << "\n";
debug << std::endl;
debug << '\n';
}
void Request::PrintIn()
{
char buf[100];
int buf_len = sizeof(buf) / sizeof(char);
int len;
debug << "fcgi input:\n";
do
{
len = FCGX_GetStr(buf, buf_len - 1, in);
if( len != 0 )
{
buf[len] = 0;
debug << buf;
}
}
while( len == buf_len - 1 );
debug << std::endl;
}
void Request::ReadEnvVariables()
{
// we store that values because FCGX_GetParam has O(n) complexity
// with this variables (env_*) we have O(1)
env_request_method = FCGX_GetParam("REQUEST_METHOD", env);
env_request_uri = FCGX_GetParam("REQUEST_URI", env);
env_http_cookie = FCGX_GetParam("HTTP_COOKIE", env);
}
void Request::CheckMethod()
{
method = none;
if( !env_request_method )
return;
if( env_request_method[0] == 'G' )
method = get;
else
if( env_request_method[0] == 'P' )
method = post;
}
void Request::ReadParameters()
{
// some parameters (get) we have always
// if( method == get )
{
GetParser get_parser(env_request_uri, get_table);
get_parser.Parse();
}
if( method == post )
{
PostParser post_parser(in, post_table);
post_parser.Parse();
}
CookieParser cookie_parser(env_http_cookie, cookie_table);
cookie_parser.Parse();
}
// reading everything
void Request::Read()
{
ReadEnvVariables();
CheckMethod();
ReadParameters();
}
void Request::SendAll()
{
if( result == redirect )
{
FCGX_PutS("Status: 301 Moved Permanently\r\n", out);
FCGX_FPrintF(out, "Location: %s\r\n", str.c_str());
log << log2 << "Redirect into: " << str << logend;
}
else
{
FCGX_PutS("Status: 200 OK\r\n", out);
FCGX_PutS("Content-Type: Text/Html\r\n", out);
}
FCGX_PutS(headers.str().c_str(), out);
FCGX_PutS("\r\n", out);
if( result == redirect )
// if there is a redirect we do not send a content
return;
FCGX_PutS(page.str().c_str(), out);
const std::string & d = debug.str();
if( !d.empty() )
{
FCGX_PutS("\n<!--\n", out);
FCGX_PutS(d.c_str(), out);
FCGX_PutS("\n-->\n", out);
}
}
// ----------------
/*
unsigned char Request::tohex(unsigned char polowa)
{
// polowa z zakresu 0-15
polowa = polowa & 0xf;
if(polowa<10)
polowa += '0';
else
polowa = polowa - 10 + 'A';
return polowa;
}
// cala wartosc zapisywana jest w postaci hex
string Request::ToHex(const string & dane)
{
string wynik;
unsigned int i;
for(i=0 ; i<dane.length() ; ++i)
{
wynik += tohex(dane[i] >> 4);
wynik += tohex(dane[i] & 0xf);
}
return wynik;
}
string Request::HexToString(const string & dane)
{
string wynik;
unsigned int i;
unsigned char znak,znak1,znak2;
if(dane.length()==0)
return wynik;
for(i=0 ; i<dane.length()-1 ; i+=2)
{
znak1 = parsujhex(dane[i]);
znak2 = parsujhex(dane[i+1]);
znak = (znak1 << 4) + znak2;
wynik += znak;
}
return wynik;
}
string Request::ToUrl(const string & dane)
{
string wynik;
unsigned int i;
for(i=0 ; i<dane.length() ; ++i)
{
if( (dane[i]>='a' && dane[i]<='z') ||
(dane[i]>='A' && dane[i]<='Z') ||
(dane[i]>='0' && dane[i]<='9') ||
dane[i]=='_' )
{
wynik += dane[i];
}
else
{
wynik += '%';
wynik += tohex(dane[i] >> 4);
wynik += tohex(dane[i] & 0xf);
}
}
return wynik;
}
*/
bool Request::AllPostVarEmpty()
{
PostTab::iterator i;
for(i=post_tab.begin() ; i!=post_tab.end() ; ++i)
if( !i->second.empty() )
return false;
return true;
}
bool Request::IsParam(const wchar_t * param_name)
{
ParamTab::iterator i;
for(i=param_tab.begin() ; i!=param_tab.end() ; ++i)
{
if( i->name == param_name )
return true;
}
return false;
}
bool Request::IsParam(const std::wstring & param_name)
{
ParamTab::iterator i;
for(i=param_tab.begin() ; i!=param_tab.end() ; ++i)
{
if( i->name == param_name )
return true;
}
return false;
}
const std::wstring & Request::ParamValue(const wchar_t * param_name)
{
ParamTab::iterator i;
for(i=param_tab.begin() ; i!=param_tab.end() ; ++i)
{
if( i->name == param_name )
return i->value;
}
return str_empty;
}

View File

@@ -1,115 +1,152 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilerequest
#define headerfilerequest
#ifndef headerfile_winix_core_request
#define headerfile_winix_core_request
#include <fcgiapp.h>
#include <sstream>
#include <vector>
#include "requesttypes.h"
#include "log.h"
#include "session.h"
#include "getparser.h"
#include "postparser.h"
#include "cookieparser.h"
#include "item.h"
#include "error.h"
#include "config.h"
#include "textstream.h"
#include "templates/htmltextstream.h"
class FunctionBase;
struct Request
{
FCGX_Stream * in, * out, * err;
FCGX_ParamArray env; // defined as 'char **'
enum Method { get, post, none } method;
// request id
// is incremented for each request and is never 0
// (from -1 will be incremented twice)
// it's used for some optimalizations e.g. in templates
size_t id;
// !! moze pozbyc sie tego none?
enum Method { get, post, head, none } method;
enum Role { responder, authorizer } role;
// headers, page and debug
std::ostringstream headers, page, debug;
//std::ostringstream headers, page, debug;
TextStream<std::string> headers;
HtmlTextStream page, debug;
// raw parameters
GetTab get_tab;
PostTab post_tab;
PostFileTab post_file_tab;
CookieTab cookie_tab;
GetTable get_table;
PostTable post_table;
CookieTable cookie_table;
// environment variables
// they are not null -- when the server doesn't have such a variable
// it will be pointing into 'char_empty' which is default '\0'
const char * env_request_method;
const char * env_request_uri;
const char * env_http_cookie;
// current session
// is set after calling session_manager.SetSession()
Session * session;
// 'done_status' is set if 'done' is different than 'nothing'
Error done_status;
// what to do
enum Result { err_internal, err404, show_dir, show_item, show_item_by_id, add_item, edit_item, del_item, del_item_confirm, confirm, redirect, logout } result; // zamienic na to_do
//Item item; // bedziemy uzywac tego, item_id i item_url_subject wywalic
const char * env_remote_addr;
const char * env_http_host;
const char * env_http_user_agent;
const char * env_http_accept_encoding;
const char * env_fcgi_role;
const char * env_content_type;
// true if the browser is Microsoft Internet Explorer
bool browser_msie;
// true if the browser is Konqueror
bool browser_konqueror;
// current directory e.g. /foo/bar
std::vector<Item> cur_dir_table;
// id of the last directory (bar) or -1
long dir;
// current directory
std::vector<Item*> dir_tab;
// items in the current directory
// maybe without contents?
std::vector<Item> item_table;
// true if a file exists
bool is_item;
// directories in the current directory
std::vector<Item> dir_table;
// this item is used for many purposes such as editing, adding an item etc.
// current file (if exists)
Item item;
// this string is used for many purposes such as redirecting
std::string str;
// current winix function
// null if there is no a function
FunctionBase * function;
// parameters (name:value)
ParamTab param_tab;
// request status
Error status;
// usually items in the current directory (depends on the function)
std::vector<Item> item_tab;
// if not empty means an address for redirecting to
std::wstring redirect_to;
std::string aredirect_to;
// send header X-LIGHTTPD-send-file with path to a file
std::wstring x_sendfile;
// send as attachment (causing header: content-disposition: attachment)
bool send_as_attachment;
// this is a pointer either to the item (if exists) or to the last directory
Item * last_item;
// for debugging
void PrintGetTable();
void PrintEnv();
void PrintIn();
Request();
void SetConfig(Config * pconfig);
void Clear();
// for debugging
void PrintGetTab();
//void PrintEnv();
void SetCookie(const char * name, const char * value);
void SetCookie(const char * name, long value);
bool IsParam(const wchar_t * param_name);
bool IsParam(const std::wstring & param_name);
const std::wstring & ParamValue(const wchar_t * param_name); // returns empty string if there is no such a parameter
bool IsPostVar(const char * var);
std::string & PostVar(const char * var); // with a throw
void SetCookie(const char * name, const char * value, tm * expires = 0);
void SetCookie(const char * name, long value, tm * expires = 0);
bool IsPostVar(const wchar_t * var);
const std::wstring & PostVar(const wchar_t * var); // !! zamienic na referencje nie do sta³ej (bez const)
bool PostVar(const wchar_t * var, std::wstring & result);
std::wstring * PostVarp(const wchar_t * var);
// item_table[0] -> item
void CopyFirstItem();
bool AllPostVarEmpty(); // returning true if all post vars are empty
void ReadEnvVariables();
void CheckMethod();
void ReadParameters();
void Read();
void SendAll();
private:
Config * config;
void ClearPostFileTmp();
// contains '\0'
// used to set env_* pointers to the empty value
const char char_empty;
// used in ParamValue() and PostVar() when there is no such a param
const std::wstring str_empty;
};
extern Request request;

View File

@@ -1,137 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#include "requestcontroller.h"
RequestController::RequestController()
{
}
bool RequestController::Init()
{
const char * sock = data.fcgi_socket.c_str();
unlink(sock);
int s = FCGX_OpenSocket(sock, 10);
if( s < 0 )
{
log << log1 << "An error during creating a socket" << logend;
return false;
}
chmod(sock, data.fcgi_socket_chmod);
passwd * pw = getpwnam(data.fcgi_socket_user.c_str());
if( !pw )
{
log << log1 << "There is no user: " << data.fcgi_socket_user << logend;
return false;
}
group * gr = getgrnam(data.fcgi_socket_group.c_str());
if( !gr )
{
log << log1 << "There is no group: " << data.fcgi_socket_group << logend;
return false;
}
chown(sock, pw->pw_uid, gr->gr_gid);
if( setuid(pw->pw_uid) < 0 )
{
log << log1 << "I can't change the user into: " << data.fcgi_socket_user << logend;
return false;
}
/*
if( setgid(gr->gr_gid) < 0 )
{
int e = errno;
log << log1 << "I can't change the group into: " << data.fcgi_socket_group << " " << gr->gr_gid << logend;
log << log1 << "errno: " << e << logend;
return false;
}
*/
dup2(s, 0);
if( !data.log_stdout )
close(1);
close(2);
//
data.dir.ReadDirs();
//
if( !content.Init() )
return false;
return true;
}
void RequestController::Loop()
{
while( FCGX_Accept(&request.in, &request.out, &request.err, &request.env) == 0 )
{
log << log2 << "start request" << logend;
try
{
request.Clear();
request.Read();
session_manager.SetSession(); // setting request.session as well
request.session->CheckTimers();
content.Make();
request.SendAll();
}
catch(const std::exception & e)
{
log << log1 << "uncaught std exception: " << e.what() << logend;
}
catch(const Error & e)
{
log << log1 << "uncaught exception: Error: " << e << logend;
}
catch(...)
{
log << log1 << "uncaught exception" << logend;
}
log << log2 << "end request" << logend;
log << log2 << "---------------------------------------------------------------------------------" << logend;
}
}

View File

@@ -1,45 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilerequestcontroller
#define headerfilerequestcontroller
#include <unistd.h>
#include <sys/stat.h>
#include <iostream>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include "data.h"
#include "log.h"
#include "request.h"
#include "content.h"
#include "sessionmanager.h"
#include "postparser.h"
#include "cookieparser.h"
class RequestController
{
Content content;
SessionManager session_manager;
public:
RequestController();
bool Init();
void Loop();
};
#endif

View File

@@ -1,26 +1,48 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilerequesttypes
#define headerfilerequesttypes
#ifndef headerfile_winix_core_requesttypes
#define headerfile_winix_core_requesttypes
#include <string>
#include <vector>
#include <map>
// some global types used by Request class
typedef std::vector<std::string> GetTable;
typedef std::map<std::string, std::string> PostTable;
typedef std::map<std::string, std::string> CookieTable;
// !! narazie uzywane tylko w post multi parserze
// dodac do zwyklego parsera post
#define WINIX_POSTTABLE_MAXSIZE 50
struct PostFile
{
std::wstring filename; // original file name
std::wstring tmp_filename; // file with content (in /tmp)
};
// parameters from get name:value
struct Param
{
std::wstring name;
std::wstring value;
};
// some global types used by Request class
typedef std::vector<std::wstring> GetTab;
typedef std::map<std::wstring, std::wstring> PostTab;
typedef std::map<std::wstring, PostFile> PostFileTab;
typedef std::vector<Param> ParamTab;
typedef std::map<std::string, std::string> CookieTab;
#endif

View File

@@ -1,13 +1,16 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "session.h"
#include "misc.h"
Session::Session()
@@ -15,59 +18,27 @@ Session::Session()
Clear();
time = std::time(0);
tm_time = Time(time);
last_time = time;
tm_last_time = tm_time;
// the first request can be a POST (it doesn't matter)
last_time_get = time;
}
void Session::Clear()
{
id = 0;
time = 0;
is_logged = false;
user_id = 0;
user.clear();
done = Done::none;
done_status = Error::ok;
item.Clear();
done_timer = 0;
}
bool Session::operator==(const Session & s) const
{
return id == s.id;
}
bool Session::operator<(const Session & s) const
{
return id < s.id;
id = 0;
time = 0;
puser = 0;
rebus_item = 0;
rebus_checked = false;
remember_me = false;
new_session = true;
spam_score = 0;
plugin_data.Resize(0);
}
bool Session::DecTimer(int & timer)
{
if( timer == 0 )
return false;
--timer;
if( timer == 0 )
return true; // we must clear our variables
return false;
}
void Session::CheckTimers()
{
if( DecTimer(done_timer) )
{
done = Done::none;
done_status = Error::ok;
}
}

View File

@@ -1,63 +1,75 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilecoresession
#define headerfilecoresession
#ifndef headerfile_winix_core_session
#define headerfile_winix_core_session
#include <ctime>
#include "requesttypes.h"
#include "error.h"
#include "item.h"
#include "done.h"
#include "error.h"
#include "user.h"
#include "plugindata.h"
#include "rebus.h"
// when deleting Sessions you should set request.session into the session object as well
// this allows to delete plugins session data
// because a session object has plugin_data object
// and in its destructor the plugin.Call(WINIX_SESSION_REMOVE) is called
struct Session
{
// 0 - means that there is no session
long id;
int time;
// 0 - means that there is a temporary session
long id;
bool is_logged;
long user_id; // logged user
// true if the session was created now
bool new_session;
std::string user; // user name
// what is done
Done done;
Error done_status;
// when this session was created
// (the same values)
time_t time;
tm tm_time;
int done_timer;
// when this session was last used
// (the same values)
time_t last_time;
tm tm_last_time;
// when there was a last get request
// (used to calculate spam)
time_t last_time_get;
// 0 - means that nobody is logged
User * puser;
// if false the session will end when the user browser is shutdown
bool remember_me;
// used for many purposes, depending on 'done'
Item item;
// rebus - set by rebus_question(Info & i) from templates
Rebus::Item * rebus_item;
bool rebus_checked;
int spam_score;
PluginData plugin_data;
// -------------------
Session();
virtual void Clear();
bool operator==(const Session & s) const;
bool operator<(const Session & s) const;
bool DecTimer(int & timer);
void CheckTimers();
void Clear();
};
#endif

161
core/sessioncontainer.cpp Executable file
View File

@@ -0,0 +1,161 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "sessioncontainer.h"
#include "log.h"
#include "misc.h"
SessionContainer::SessionContainer()
{
table_size = 0;
}
void SessionContainer::SetCur(Cur * pcur)
{
cur = pcur;
}
void SessionContainer::SetConfig(Config * pconfig)
{
config = pconfig;
}
void SessionContainer::SetTmpSession(Session * psession)
{
tmp_session = psession;
}
void SessionContainer::Clear()
{
Table::iterator i = table.begin();
log << log3 << "SC: deleting all sessions" << logend;
// don't use table.clear();
// because plugins session data would not be erased
// we must set cur->session for each session and then delete it
while( i != table.end() )
{
cur->session = &(*i);
table.erase(i++);
}
// erasing indexes
index_id.clear();
table_size = 0;
cur->session = tmp_session;
}
void SessionContainer::EraseById(IdIterator i)
{
Session * old_session = tmp_session;
if( cur->session != &(*i->second) )
old_session = cur->session;
cur->session = &(*i->second);
log << log4 << "SC: deleting session, id: " << i->second->id << logend;
table.erase(i->second);
index_id.erase(i);
table_size -= 1;
cur->session = old_session;
}
size_t SessionContainer::Size()
{
// don't use table.size() as it has O(n) complexity on FreeBSD
return table_size;
}
SessionContainer::Iterator SessionContainer::Begin()
{
return table.begin();
}
SessionContainer::Iterator SessionContainer::End()
{
return table.end();
}
Session & SessionContainer::Back()
{
return table.back();
}
SessionContainer::IdIterator SessionContainer::IdBegin()
{
return index_id.begin();
}
SessionContainer::IdIterator SessionContainer::IdEnd()
{
return index_id.end();
}
bool SessionContainer::PushBack(const Session & session)
{
std::pair<IndexId::iterator, bool> index_id_res = index_id.insert( std::make_pair(session.id, table.end()) );
if( !index_id_res.second )
{
// that element already exists (was not inserted now)
return false;
}
Iterator last = table.insert(table.end(), session);
index_id_res.first->second = last;
table_size += 1;
log << log3 << "SC: added session, id: " << session.id << logend;
return true;
}
SessionContainer::Iterator SessionContainer::FindById(long id)
{
IndexId::iterator i;
i = index_id.find(id);
if( i == index_id.end() )
return table.end();
return i->second;
}

73
core/sessioncontainer.h Executable file
View File

@@ -0,0 +1,73 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_sessioncontainer
#define headerfile_winix_core_sessioncontainer
#include <list>
#include <map>
#include <ctime>
#include "session.h"
#include "cur.h"
#include "config.h"
class SessionContainer
{
public:
// when deleting Sessions you should set request.session into the session object
// this allows to delete plugins session data
// because a session object has plugin_data object
// and in its destructor the plugin.Call(WINIX_SESSION_REMOVE) is called
typedef std::list<Session> Table;
typedef Table::iterator Iterator;
typedef std::map<long, Iterator> IndexId;
typedef IndexId::iterator IdIterator;
SessionContainer();
void SetCur(Cur * pcur);
void SetConfig(Config * pconfig);
void SetTmpSession(Session * psession);
void Clear();
size_t Size();
Iterator Begin();
Iterator End();
Session & Back();
bool PushBack(const Session & session);
Iterator FindById(long);
IdIterator IdBegin();
IdIterator IdEnd();
void EraseById(IdIterator i);
private:
Table table;
IndexId index_id;
Cur * cur;
Config * config;
Session * tmp_session;
// in FreeBSD implementation (GCC) list::size() has linear complexity
// so we use our own table_size with O(1)
size_t table_size;
};
#endif

View File

@@ -1,34 +1,79 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include <sys/stat.h>
#include "sessionmanager.h"
#include "request.h"
#include "log.h"
#include "session.h"
#include "sessionparser.h"
#include "plugin.h"
bool SessionManager::IsSession(long s)
SessionManager::SessionManager()
{
SessionTable::iterator i;
Session temp;
temp.id = s;
i = session_table.find(temp);
if( i == session_table.end() )
temporary_session.id = 0;
session = &temporary_session;
session_tab.SetTmpSession(&temporary_session);
// thread work mode
work_mode = 1;
}
void SessionManager::SetCur(Cur * pcur)
{
cur = pcur;
session_tab.SetCur(pcur);
}
void SessionManager::SetConfig(Config * pconfig)
{
config = pconfig;
session_tab.SetConfig(pconfig);
}
void SessionManager::SetSystem(System * psystem)
{
system = psystem;
}
void SessionManager::SetLastContainer(LastContainer * plast_container)
{
last_container = plast_container;
}
size_t SessionManager::Size()
{
return session_tab.Size();
}
bool SessionManager::IsSession(long id)
{
if( session_tab.FindById(id) == session_tab.End() )
return false;
return true;
}
long SessionManager::CreateSessionId()
{
long id;
@@ -59,90 +104,111 @@ return id;
}
void SessionManager::CreateTemporarySession()
{
Session s;
s.id = 0;
SessionTable::iterator i = session_table.find( s ); // looking for id=0
if( i == session_table.end() )
{
std::pair<SessionTable::iterator,bool> res = session_table.insert(s);
request.session = const_cast<Session*>( &(*res.first) );
}
else
{
request.session = const_cast<Session*>( &(*i) );
}
}
void SessionManager::CreateSession()
{
Session s;
int attempts = 100;
int attempts = 100;
bool added = false;
for( ; attempts > 0 ; --attempts )
new_session.Clear();
if( config->session_max == 0 || session_tab.Size() < config->session_max )
{
s.id = CreateSessionId();
std::pair<SessionTable::iterator,bool> res = session_table.insert(s);
if( res.second == true )
for( ; !added && attempts > 0 ; --attempts )
{
// the insertion took place
request.session = const_cast<Session*>( &(*res.first) );
request.SetCookie(data.http_session_id_name.c_str(), request.session->id);
log << log1 << "created a new session: " << s.id << logend;
return;
new_session.id = CreateSessionId();
added = session_tab.PushBack(new_session);
}
}
else
{
log << log2 << "SM: sessions limit exceeded (" << config->session_max << ")" << logend;
}
if( added )
{
session = &session_tab.Back();
session->new_session = true;
log << log2 << "SM: created a new session: " << session->id << logend;
}
else
{
// there is a problem with generating a new session id
// we do not set a session cookie
session = &temporary_session;
session->Clear();
session->new_session = false; // temporary session was initialized at the beginning
log << log1 << "SM: cannot create a session id (temporary used: with id 0)" << logend;
}
}
bool SessionManager::SetSessionFromCookie(const std::string & cookie)
{
long id = Tol(cookie.c_str());
SessionContainer::Iterator s = session_tab.FindById(id);
if( s == session_tab.End() )
return false;
// there is a problem with generating a new session id
// we do not set a session cookie
CreateTemporarySession();
log << log1 << "cannot create a session id (temporary used: with id 0)" << logend;
// that session is in the table
session = &(*s);
session->new_session = false;
session->last_time = std::time(0);
session->tm_last_time = Time(session->last_time);
if( cur->request->method == Request::get )
session->last_time_get = session->last_time;
log << log2 << "SM: session: " << session->id;
if( session->puser )
log << log2 << ", user: " << session->puser->name << ", id: " << session->puser->id;
log << log2 << logend;
return true;
}
void SessionManager::SetSession()
{
CookieTable::iterator i = request.cookie_table.find(data.http_session_id_name);
if( i == request.cookie_table.end() )
CookieTab::iterator i = cur->request->cookie_tab.find(config->http_session_id_name);
if( i == cur->request->cookie_tab.end() )
{
CreateSession();
}
else
{
Session temp;
temp.id = atol(i->second.c_str());
SessionTable::iterator s = session_table.find(temp);
if( s != session_table.end() )
{
// that session is in the table
request.session = const_cast<Session*>( &(*s) );
log << log1 << "session: " << s->id << logend;
}
else
if( !SetSessionFromCookie(i->second) )
{
// there is no such a session
// deleting the old cookie
request.cookie_table.erase(i);
cur->request->cookie_tab.erase(i);
// and creating a new one
CreateSession();
}
}
// request.session is set now
}
SessionContainer::Iterator SessionManager::SessionBegin()
{
return session_tab.Begin();
}
SessionContainer::Iterator SessionManager::SessionEnd()
{
return session_tab.End();
}
@@ -150,12 +216,221 @@ void SessionManager::SetSession()
void SessionManager::DeleteSessions()
{
session_tab.Clear();
}
void SessionManager::InitTmpSession()
{
Session * old_session = cur->session;
log << log4 << "SM: initializing temporary session" << logend;
cur->session = &temporary_session;
plugin.Call(WINIX_SESSION_CREATED);
cur->session = old_session;
}
void SessionManager::UninitTmpSession()
{
Session * old_session = cur->session;
log << log4 << "SM: uninitializing temporary session" << logend;
cur->session = &temporary_session;
cur->session->plugin_data.DeleteAll(); // this will call plugin.Call(WINIX_SESSION_REMOVE);
cur->session->plugin_data.Resize(0);
cur->session = old_session;
}
void SessionManager::LoadSessions()
{
SessionParser sp;
SessionContainer::Iterator i;
// sessions will be overwritten (pointers are invalidated)
cur->session = &temporary_session;
sp.SetUsers(&system->users);
sp.Parse(config->session_file, session_tab);
for(i=session_tab.Begin() ; i != session_tab.End() ; ++i)
{
i->plugin_data.Resize(plugin.Size());
cur->session = &(*i);
plugin.Call(WINIX_SESSION_CREATED);
}
cur->session = &temporary_session;
}
void SessionManager::SaveSessions()
{
if( config->session_file.empty() )
return;
std::ofstream file(config->session_file.c_str());
if( !file )
{
log << log1 << "SM: cannot open the session file for writing - sessions lost" << logend;
return;
}
log << log2 << "SM: saving sessions" << logend;
long len = 0;
SessionContainer::Iterator i = session_tab.Begin();
for( ; i!=session_tab.End() ; ++i )
{
if( i->id != 0 && i->puser )
{
file << i->id << ' ' << i->puser->id << ' ' << i->remember_me << ' ';
file << (long)i->time << ' ' << (long)i->last_time << std::endl;
++len;
}
}
file.close();
chmod(config->session_file.c_str(), 0600);
log << log2 << "SM: saved " << len << " session(s)" << logend;
}
Session * SessionManager::GetTmpSession()
{
return &temporary_session;
}
Session * SessionManager::GetCurSession()
{
return session;
}
/*
*
*
* sessions gc (second thread)
*
*
*/
void SessionManager::Work()
{
bool exit = false;
SessionContainer::IndexId::iterator i;
deleted = 0;
Lock();
i = session_tab.IdBegin();
Unlock();
while( !exit )
{
Lock();
CheckSession(i);
exit = synchro->was_stop_signal;
Unlock();
}
}
// it's called from the other thread (with Lock and Unlock)
void SessionManager::CheckSession(SessionContainer::IndexId::iterator & i)
{
const int deleted_max_at_once = 10;
if( i == session_tab.IdEnd() )
{
if( deleted > 0 )
{
deleted = 0;
log << logsave;
}
i = session_tab.IdBegin();
WaitForSignalSleep(10);
}
else
{
if( IsSessionOutdated(*i->second) )
{
DeleteSession(i++);
++deleted;
}
else
{
++i;
}
if( deleted >= deleted_max_at_once )
{
log << logsave;
WaitForSignalSleep(1);
deleted = 0;
}
}
}
// it's called from the other thread (with Lock and Unlock)
bool SessionManager::IsSessionOutdated(const Session & s) const
{
bool outdated;
if( s.remember_me )
outdated = s.last_time < std::time(0) - config->session_remember_max_idle;
else
outdated = s.last_time < std::time(0) - config->session_max_idle;
return outdated;
}
// it's called from the other thread (with Lock and Unlock)
void SessionManager::DeleteSession(SessionContainer::IdIterator i)
{
Session * del_session = &(*i->second);
if( del_session->puser )
last_container->UserLogout(del_session->puser->id, del_session->id);
session_tab.EraseById(i);
}
/*
*
*
* end of sessions gc
*
*
*/

View File

@@ -1,44 +1,89 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfilesessionmanager
#define headerfilesessionmanager
#ifndef headerfile_winix_core_sessionmanager
#define headerfile_winix_core_sessionmanager
#include <set>
#include <ctime>
#include "sessioncontainer.h"
#include "config.h"
#include "request.h"
#include "log.h"
#include "data.h"
#include "session.h"
#include "db.h"
#include "lastcontainer.h"
#include "system.h"
#include "synchro.h"
#include "basethread.h"
class SessionManager
class SessionManager : public BaseThread
{
// !! zamienic na map
typedef std::set<Session> SessionTable;
SessionTable session_table;
public:
SessionManager();
void SetCur(Cur * pcur);
void SetConfig(Config * pconfig);
void SetSystem(System * psystem);
void SetLastContainer(LastContainer * plast_container);
void SetSession();
void DeleteSessions(); // deleting all sessions
void InitTmpSession();
void UninitTmpSession();
Session * GetTmpSession();
Session * GetCurSession();
void LoadSessions();
void SaveSessions();
SessionContainer::Iterator SessionBegin();
SessionContainer::Iterator SessionEnd();
size_t Size();
private:
Config * config;
Cur * cur;
System * system;
LastContainer * last_container;
// current session - set by SetSession()
Session * session;
SessionContainer session_tab;
// session with id 0
Session temporary_session;
// for adding a new session to the container
Session new_session;
bool IsSession(long s);
long CreateSessionId();
void CreateTemporarySession();
void CreateSession();
public:
bool SetSessionFromCookie(const std::string & cookie);
void SetSession();
// second thread
int deleted;
virtual void Work();
void CheckSession(SessionContainer::IndexId::iterator & i);
bool IsSessionOutdated(const Session & s) const;
void DeleteSession(SessionContainer::IdIterator i);
};

166
core/sessionparser.cpp Executable file
View File

@@ -0,0 +1,166 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "sessionparser.h"
#include "log.h"
#include "misc.h"
bool SessionParser::Parse(const std::string & path, SessionContainer & container)
{
return Parse(path.c_str(), container);
}
void SessionParser::SetUsers(Users * pusers)
{
users = pusers;
}
bool SessionParser::Parse(const char * path, SessionContainer & container)
{
container.Clear();
file.open(path, std::ios_base::in | std::ios_base::binary);
if( !file )
{
log << log1 << "SP: cannot open the session file for reading (file: '" << path << "')" << logend;
return false;
}
bool res = Parse(container);
file.close();
return res;
}
bool SessionParser::Parse(SessionContainer & container)
{
/*
file format, each rows:
session_id(long) user_id(long) remember_me(0|1) time(long) last_time(long)
*/
long user_id;
session.Clear();
last = file.get();
log << log2 << "SP: reading sessions from the session file" << logend;
while( true )
{
session.id = ReadLong();
if( file.eof() )
break;
user_id = ReadLong();
session.remember_me = ReadLong();
session.time = ReadLong();
session.last_time = ReadLong();
if( MakeSession(user_id) )
{
users->IncrementLoggedUsers();
container.PushBack(session);
log << log2 << "SP: read session id: " << session.id << " for user: " << session.puser->name << logend;
}
SkipLine();
}
log << log2 << "SP: read " << container.Size() << " session(s)" << logend;
return true;
}
bool SessionParser::MakeSession(long user_id)
{
User * puser = users->GetUser(user_id);
if( !puser )
{
log << log1 << "SP: there is no a user with id: " << user_id << " (skipped)" << logend;
return false;
}
session.puser = puser;
session.new_session = true;
session.tm_time = Time(session.time);
session.tm_last_time = Time(session.last_time);
return true;
}
bool SessionParser::IsWhite(int c)
{
if( c==' ' || c=='\t' || c==13 )
return true;
return false;
}
bool SessionParser::IsDigit(int c)
{
if( c>='0' && c<='9' )
return true;
return false;
}
void SessionParser::SkipWhite()
{
while( IsWhite(last) )
last = file.get();
}
void SessionParser::SkipLine()
{
while( last != 10 )
last = file.get();
last = file.get(); // first character from the new line
}
long SessionParser::ReadLong()
{
long res = 0;
bool is_sign = false;
SkipWhite();
if( last == '-' )
{
is_sign = true;
last = file.get();
}
while( IsDigit(last) )
{
res = res*10 + (last-'0');
last = file.get();
}
if( is_sign )
res = -res;
return res;
}

51
core/sessionparser.h Executable file
View File

@@ -0,0 +1,51 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_sessionparser
#define headerfile_winix_core_sessionparser
#include <fstream>
#include <string>
#include "session.h"
#include "sessioncontainer.h"
#include "users.h"
class SessionParser
{
public:
bool Parse(const char * path, SessionContainer & container);
bool Parse(const std::string & path, SessionContainer & container);
void SetUsers(Users * pusers);
private:
Users * users;
bool Parse(SessionContainer & container);
bool MakeSession(long user_id);
bool IsWhite(int c);
bool IsDigit(int c);
void SkipWhite();
void SkipLine();
long ReadLong();
std::ifstream file;
int last; // last character
Session session;
};
#endif

35
core/synchro.cpp Executable file
View File

@@ -0,0 +1,35 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "synchro.h"
Synchro::Synchro() : mutex(PTHREAD_MUTEX_INITIALIZER)
{
was_stop_signal = false;
}
bool Synchro::Lock()
{
return pthread_mutex_lock(&mutex) == 0;
}
void Synchro::Unlock()
{
pthread_mutex_unlock(&mutex);
}

36
core/synchro.h Executable file
View File

@@ -0,0 +1,36 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_synchro
#define headerfile_winix_core_synchro
#include <pthread.h>
struct Synchro
{
// one global mutex
pthread_mutex_t mutex;
// true when winix is closing
volatile bool was_stop_signal;
Synchro();
bool Lock();
void Unlock();
};
#endif

964
core/system.cpp Executable file
View File

@@ -0,0 +1,964 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "system.h"
#include "misc.h"
#include "error.h"
#include "templates/templates.h"
#include "functions/functionbase.h"
void System::SetCur(Cur * pcur)
{
cur = pcur;
}
void System::SetConfig(Config * pconfig)
{
config = pconfig;
}
void System::SetDb(Db * pdb)
{
db = pdb;
}
void System::SetSynchro(Synchro * psynchro)
{
synchro = psynchro;
}
void System::Init()
{
dirs.SetDb(db);
dirs.SetCur(cur);
dirs.SetNotify(&notify);
dirs.ReadDirs();
mounts.SetDirs(&dirs);
mounts.SetDb(db);
mounts.SetCur(cur);
mounts.CreateMounts();
mounts.ReadMounts();
users.SetCur(cur);
users.ReadUsers(db);
users.SetTimeZoneOffset(config->time_zone_offset);
groups.ReadGroups(db); // !! chwilowe przekazanie argumentu, db bedzie zmienione
rebus.SetCur(cur);
rebus.Init();
notify.SetSynchro(synchro);
notify.SetCur(cur);
notify.SetConfig(config);
notify.SetUsers(&users);
notify.SetDirs(&dirs);
notify.Init();
thumb.SetSynchro(synchro);
thumb.SetDb(db);
thumb.SetConfig(config);
thumb.SetSystem(this);
}
// !! mozna zrobic jakas obsluge kiedy nie mozemy sie redirectnac, np gdy wystapil blad
// !! moze zwracac jakas wartosc?
void System::RedirectTo(const Item & item, const wchar_t * postfix)
{
cur->request->redirect_to = config->base_url;
if( item.type == Item::dir )
{
// item_id is pointing to a directory
dirs.MakePath(item.id, cur->request->redirect_to, false);
}
else
{
// item_id is pointing to a file or a symlink
if( dirs.MakePath(item.parent_id, cur->request->redirect_to, false) )
cur->request->redirect_to += item.url;
}
if( postfix )
cur->request->redirect_to += postfix;
}
void System::RedirectTo(long item_id, const wchar_t * postfix)
{
cur->request->redirect_to = config->base_url;
Item * pdir = dirs.GetDir(item_id);
if( pdir )
{
// item_id is pointing to a directory
dirs.MakePath(pdir->id, cur->request->redirect_to, false);
}
else
{
// item_id is pointing to a file
DbItemQuery iq;
iq.SetAllSel(false);
iq.WhereId(item_id);
iq.sel_parent_id = true;
iq.sel_url = true;
if( db->GetItem(item_temp, iq) == WINIX_ERR_OK )
{
if( dirs.MakePath(item_temp.parent_id, cur->request->redirect_to, false) )
cur->request->redirect_to += item_temp.url;
}
else
{
log << log1 << "System: can't redirect: no such item: id: " << item_id << logend;
}
}
if( postfix )
cur->request->redirect_to += postfix;
}
void System::RedirectTo(const std::wstring & url)
{
cur->request->redirect_to = config->base_url;
if( !url.empty() && url[0] == '/' )
{
// absolute path
cur->request->redirect_to += url;
}
else
{
// relative path
if( !cur->request->dir_tab.empty() )
{
if( dirs.MakePath(cur->request->dir_tab.back()->id, cur->request->redirect_to, false) )
cur->request->redirect_to += url;
}
else
{
cur->request->redirect_to += '/';
cur->request->redirect_to += url;
}
}
}
void System::AddParams(const ParamTab & param_tab, std::wstring & str, bool clear_str)
{
if( clear_str )
str.clear();
for(size_t i=0 ; i<param_tab.size() ; ++i)
{
str += '/';
str += param_tab[i].name;
if( !param_tab[i].value.empty() )
{
str += ':';
str += param_tab[i].value;
}
}
}
void System::RedirectWithFunctionAndParamsTo(const std::wstring & url)
{
RedirectTo(url);
if( !cur->request->function )
return;
cur->request->redirect_to += '/';
cur->request->redirect_to += cur->request->function->fun.url;
AddParams(cur->request->param_tab, cur->request->redirect_to, false);
}
void System::RedirectToLastDir()
{
if( !cur->request->dir_tab.empty() )
RedirectTo( *cur->request->dir_tab.back() );
}
void System::RedirectToLastItem()
{
if( cur->request->last_item )
RedirectTo( *cur->request->last_item );
}
bool System::CanChangeUser(const Item & item, long new_user_id)
{
if( !cur->session )
// session must be set
return false;
if( cur->session->puser && cur->session->puser->super_user )
// super user is allowed everything
return true;
// !! przeciez to prosciej mozna zapisac
// albo dac od razu return false
if( item.user_id != new_user_id )
// only super user can change the owner of an item
return false;
return true;
}
bool System::CanChangeGroup(const Item & item, long new_group_id)
{
if( !cur->session )
// session must be set
return false;
if( cur->session->puser && cur->session->puser->super_user )
// super user is allowed everything
return true;
if( item.group_id != new_group_id )
{
// user is allowed to change the group only if he is an owner of the item
// he can change only into a group in which he is a member of, or into a 'no_group'
if( !cur->session->puser )
return false;
if( cur->session->puser->id != item.user_id )
return false;
if( new_group_id == -1 )
return true;
if( !cur->session->puser->IsMemberOf(new_group_id) )
return false;
// is logged, is the owner of the item, is the member of the new group
}
return true;
}
bool System::CanChangePrivileges(const Item & item, int new_priv)
{
if( !cur->session )
// session must be set
return false;
if( cur->session->puser && cur->session->puser->super_user )
// super user is allowed everything
return true;
if( item.privileges != new_priv )
{
// the owner of an item is allowed to change the privileges
if( !cur->session->puser )
return false;
if( cur->session->puser->id != item.user_id )
return false;
}
return true;
}
bool System::HasAccess(const Item & item, int mask)
{
if( !cur->session )
// session must be set
return false;
if( cur->session->puser && cur->session->puser->super_user )
// super user is allowed everything
return true;
if( cur->session->puser && cur->session->puser->id == item.user_id )
{
// the owner
return ((item.privileges >> 6) & mask) == mask;
}
if( cur->session->puser && cur->session->puser->IsMemberOf(item.group_id) )
{
// group
return ((item.privileges >> 3) & mask) == mask;
}
// others
return (item.privileges & mask) == mask;
}
bool System::HasReadAccess(const Item & item)
{
return HasAccess(item, 4);
}
bool System::HasWriteAccess(const Item & item)
{
return HasAccess(item, 2);
}
bool System::HasReadWriteAccess(const Item & item)
{
return HasAccess(item, 6); // r+w
}
bool System::HasReadExecAccess(const Item & item)
{
if( cur->session && cur->session->puser && cur->session->puser->super_user )
{
// there must be at least one 'x' (for the root)
return (item.privileges & 0111) != 0;
}
return HasAccess(item, 5); // r+x
}
bool System::HasReadExecAccessToPath(long dir_id)
{
while( true )
{
Item * pdir = dirs.GetDir(dir_id);
if( !pdir )
return false;
if( !HasReadExecAccess(*pdir) )
return false;
dir_id = pdir->parent_id;
if( dir_id == -1 )
return true;
}
}
bool System::HasReadExecAccessToPath(const std::vector<Item*> & dir_tab)
{
for(size_t i=0 ; i < dir_tab.size() ; ++i)
{
if( !HasReadExecAccess(*dir_tab[i]) )
return false;
}
return true;
}
bool System::DirsHaveReadExecPerm()
{
return HasReadExecAccessToPath(cur->request->dir_tab);
}
// if we don't have access we only remove the item from the table
void System::CheckAccessToItems(std::vector<Item> & item_tab)
{
size_t i = 0;
while( i < item_tab.size() )
{
if( !HasReadAccess(item_tab[i]) )
{
item_tab.erase(item_tab.begin() + i);
}
else
{
i += 1;
}
}
}
bool System::CanUseHtml(long user_id)
{
return IsMemberOfGroup(user_id, L"allow_html");
}
bool System::CanUseBBCode(long user_id)
{
// logged users can use bbcode
return (user_id != -1);
}
bool System::CanUseRaw(long user_id)
{
return IsMemberOfGroup(user_id, L"allow_raw");
}
bool System::IsMemberOfGroup(long user_id, const wchar_t * group_name)
{
User * puser = users.GetUser(user_id);
if( !puser )
return false;
if( puser->super_user )
return true; // !! ?? zakladamy ze administrator jest czlonkiem wszystkich grup? dlaczego?
long group = groups.GetGroupId(group_name);
if( group == -1 )
// there is no such a group
return false;
return puser->IsMemberOf(group);
}
// the path depends on parent_id
bool System::CreateNewFileSimpleFs(Item & item)
{
bool res = dirs.MakePath(item.parent_id, item.file_path);
if( res )
{
if( !item.file_path.empty() && item.file_path[0] == '/' )
item.file_path.erase(0, 1);
}
else
{
log << log1 << "System: CreateNewFileSimpleFs: can't create a path to item.id: " << item.id
<< ", item.parent_id: " << item.parent_id << logend;
}
return res;
}
// the path depends on id
bool System::CreateNewFileHashFs(Item & item)
{
wchar_t buffer[50];
wchar_t * hash = buffer;
size_t buffer_len = sizeof(buffer)/sizeof(wchar_t);
// get 'id' as hexadecimal
buffer[0] = '0';
swprintf(buffer+1, buffer_len, L"%lx", (unsigned long)item.id);
item.file_path.clear();
// make sure that the length is even
if( (wcslen(hash) & 1) != 0 )
hash = buffer + 1; // the first character was zero
for(size_t i=0 ; hash[i] != 0 ; i+=2)
{
item.file_path += hash[i];
item.file_path += hash[i+1];
if( hash[i+2] != 0 )
item.file_path += '/';
}
// one character more to make sure the path is unique
// (we can have a directory without the character)
item.file_path += '_';
return true;
}
// creating item.file_path and item.file_fs
// you should set file_type yourself
// this method uses: item.id, item.url, item.parent_id (for selecting a mountpoint)
bool System::CreateNewFile(Item & item)
{
bool res;
if( item.type != Item::file )
{
log << log1 << "System: CreateNewFile: the item should be a file" << logend;
return false;
}
Mount * pmount = mounts.CalcMount(item.parent_id);
if( !pmount || pmount->fs != mounts.MountFsHashfs() )
{
res = CreateNewFileSimpleFs(item);
item.file_fs = mounts.MountFsSimplefs();
}
else
{
res = CreateNewFileHashFs(item);
item.file_fs = mounts.MountFsHashfs();
}
if( res )
item.file_path += item.url;
else
item.file_path.clear();
return res;
}
// making a global file path (in the unix file system)
// you should call CreateNewFile before
bool System::MakeFilePath(const Item & item, std::wstring & path, bool thumb, bool create_dir, int chmod)
{
path.clear();
if( config->upload_dir.empty() )
{
log << log1 << "System: MakePath: upload_dir is not set in the config file" << logend;
return false;
}
if( item.file_path.empty() || item.file_type == WINIX_ITEM_FILETYPE_NONE )
{
log << log1 << "System: MakePath: this item has not a static file" << logend;
return false;
}
path = config->upload_dir;
if( item.file_fs == mounts.MountFsHashfs() )
path += L"/hashfs";
else
path += L"/simplefs";
if( thumb )
path += L"/thumb";
else
path += L"/normal";
if( create_dir && !CreateDirs(path, item.file_path, chmod, true) )
return false;
path += '/';
path += item.file_path;
return true;
}
// item can be a directory, file or a symlink
// if item is a directory then the path will be with a slash at the end
bool System::MakePath(const Item & item, std::wstring & path, bool clear_path)
{
bool res;
if( clear_path )
path.clear();
if( item.type == Item::dir )
{
res = dirs.MakePath(item.id, path);
}
else
{
res = dirs.MakePath(item.parent_id, path);
if( res )
path += item.url;
}
return res;
}
Error System::AddFile(Item & item, int notify_code)
{
if( item.type != Item::file )
return WINIX_ERR_FILE_EXPECTED;
Error status = db->AddItem(item);
if( status == WINIX_ERR_OK )
{
log << log2 << "System: added a new file, url: " << item.url << ", id: " << item.id
<< ", parent_id: " << item.parent_id << logend;
if( notify_code )
notify.ItemChanged(notify_code, item);
}
return status;
}
Error System::EditFile(Item & item, bool with_url, int notify_code)
{
if( item.type != Item::file )
return WINIX_ERR_FILE_EXPECTED;
if( cur->session && cur->session->puser )
cur->request->item.modification_user_id = cur->session->puser->id;
else
cur->request->item.modification_user_id = -1;
item.SetDateModifyToNow();
Error status = db->EditItemById(item, with_url);
if( status == WINIX_ERR_OK )
{
TemplatesFunctions::pattern_cacher.UpdatePattern(item);
log << log2 << "System: modified an item" << logend;
if( notify_code )
notify.ItemChanged(notify_code, item);
}
return status;
}
time_t System::LocalTime(time_t gmt_time)
{
int time_offset;
if( cur->session && cur->session->puser )
time_offset = cur->session->puser->time_zone_offset;
else
time_offset = config->time_zone_offset_guest;
return gmt_time + (time_t)time_offset;
}
tm System::LocalTime(const tm * ptm)
{
time_t t;
tm rtm;
t = Time(ptm);
t = LocalTime(t);
rtm = Time(t);
return rtm;
}
tm System::LocalTime(const tm & ptm)
{
return LocalTime(&ptm);
}
/*
return codes:
ok:
0 - the link_to is a path to a directory (out_item skipped, out_dir_tab will not be empty)
1 - the link_to is a path to a file or a symlink (out_item is used, out_dir_tab will not be empty)
error:
2 - incorrect link_to
3 - there is not a root dir
4 - current_dir_tab was empty
current_dir_tab can be the same container as out_dir_tab
link_to can be a relative path (without the first slash)
*/
int System::FollowLink(const std::vector<Item*> & current_dir_tab, const std::wstring & link_to,
std::vector<Item*> & out_dir_tab, Item & out_item)
{
link_to_temp = link_to; // copy the link because it can be from out_item (and will be cleared)
out_item.Clear();
int res = dirs.FollowLink(current_dir_tab, link_to_temp, out_dir_tab, name_temp);
if( res == 1 )
{
if( db->GetItem(out_dir_tab.back()->id, name_temp, out_item) == WINIX_ERR_OK )
return 1;
else
return 2;
}
return res;
}
bool System::FollowAllLinksDirFound(std::vector<Item*> & out_dir_tab,
bool follow_dir_default, bool stop_on_link_redirect, bool check_access)
{
log << log3 << "System: link to a directory: ";
dirs.LogDir(out_dir_tab);
log << logend;
if( check_access && !HasReadExecAccessToPath(out_dir_tab) )
{
log << log1 << "System: no access to the directory structure" << logend;
return false;
}
if( !out_dir_tab.back()->link_to.empty() )
{
if( follow_dir_default )
{
if( !(stop_on_link_redirect && out_dir_tab.back()->link_redirect==1) )
link_to_temp = out_dir_tab.back()->link_to;
}
}
return true;
}
bool System::FollowAllLinksFileOrSymlinkFound(std::vector<Item*> & out_dir_tab, Item & out_item,
bool stop_on_link_redirect, bool check_access)
{
if( out_item.type == Item::symlink )
log << log3 << "System: link to a symlink: ";
else
log << log3 << "System: link to a file: ";
dirs.LogDir(out_dir_tab);
log << out_item.url << logend;
if( check_access && !HasReadExecAccessToPath(out_dir_tab) )
{
log << log1 << "System: no access to the directory structure" << logend;
return false;
}
if( out_item.type == Item::symlink )
{
if( out_item.link_to.empty() )
{
log << log1 << "System: symlink empty" << logend;
return false;
}
else
{
if( !check_access || HasReadAccess(out_item) )
{
if( !(stop_on_link_redirect && out_item.link_redirect==1) )
link_to_temp = out_item.link_to;
}
else
{
log << log1 << "System: no read access to the symlink" << logend;
return false;
}
}
}
return true;
}
/*
return codes:
ok:
0 - the link_to is a path to a directory (out_item skipped, out_dir_tab will not be empty)
1 - the link_to is a path to a file (out_item is used, out_dir_tab will not be empty)
(link_to can be a path to a symlink if stop_on_link_redirect is true)
error:
2 - incorrect link_to
3 - there is not a root dir
4 - current_dir_tab was empty
5 - limit of symlinks exceeded
6 - permission denied to a file/symlink or a directory (or a symlink is empty)
current_dir_tab can be the same container as out_dir_tab
link_to can be a relative path (without the first slash)
if follow_dir_default is true then directories with 'default' flags are followed as well
if stop_on_link_redirect is true then the method stops on a symbolic link (or a directory
with 'default' flag set) where the redirection should be done, you should check then whether
the out_item.back()->link_to is not empty (if the result was 0 ) or
whether out_item.type is symlink (if the result was 1)
to make the redirection
*/
int System::FollowAllLinks(const std::vector<Item*> & current_dir_tab, const std::wstring & link_to,
std::vector<Item*> & out_dir_tab, Item & out_item,
bool follow_dir_default, bool stop_on_link_redirect, bool check_access)
{
int res;
size_t level = 0;
link_to_temp = link_to;
if( current_dir_tab.empty() )
return 4;
do
{
if( ++level > config->symlinks_follow_max )
{
log << log1 << "System: the number of maximum symlinks exceeded ("
<< config->symlinks_follow_max << ")" << logend;
res = 5;
}
else
{
res = FollowLink(current_dir_tab, link_to_temp, out_dir_tab, out_item);
link_to_temp.clear();
if( res == 0 )
{
out_item.Clear();
res = FollowAllLinksDirFound(out_dir_tab, follow_dir_default, stop_on_link_redirect, check_access) ? 0 : 6;
}
else
if( res == 1 )
{
res = FollowAllLinksFileOrSymlinkFound(out_dir_tab, out_item, stop_on_link_redirect, check_access) ? 1 : 6;
}
else
{
log << log2 << "System: incorrect link: " << link_to << logend;
}
}
}
while( !link_to_temp.empty() );
return res;
}
// the same as FollowAllLinks but starts from the root directory
// link_to must begin with a slash (or can be empty then the root directory is returned)
int System::FollowAllLinks(const std::wstring & link_to,
std::vector<Item*> & out_dir_tab, Item & out_item,
bool follow_dir_default, bool stop_on_link_redirect, bool check_access)
{
if( !link_to.empty() && link_to[0] != '/' )
return 2;
if( root_follow_dir_tab.size() != 1 )
root_follow_dir_tab.resize(1);
Item * root_dir = dirs.GetRootDir();
if( !root_dir )
return 3;
root_follow_dir_tab[0] = root_dir;
return FollowAllLinks(root_follow_dir_tab, link_to,
out_dir_tab, out_item, follow_dir_default, stop_on_link_redirect, check_access);
}
// the same as FollowAllLinks but operates on cur->request->dir_tab and cur->request->item
// and returns bool
// the method is making a redirection if needed
bool System::FollowAllLinks(const std::wstring & link_to,
bool follow_dir_default, bool stop_on_link_redirect, bool check_access)
{
int res = FollowAllLinks(cur->request->dir_tab, link_to, temp_follow_dir_tab, temp_follow_item,
follow_dir_default, stop_on_link_redirect, check_access);
bool ok = (res == 0 || res == 1);
if( ok )
{
cur->request->dir_tab = temp_follow_dir_tab;
if( res == 0 )
{
cur->request->is_item = false;
cur->request->item.Clear();
cur->request->last_item = cur->request->dir_tab.back();
if( !cur->request->dir_tab.back()->link_to.empty() )
RedirectTo(cur->request->dir_tab.back()->link_to);
log << log3 << "System: current directory changed" << logend;
}
else
{
cur->request->is_item = true;
cur->request->item = temp_follow_item;
cur->request->last_item = &cur->request->item;
if( cur->request->item.type == Item::symlink )
RedirectTo(cur->request->item.link_to); // cur->request->item.link_to is not empty
log << log3 << "System: current directory changed and the new file loaded" << logend;
}
mounts.CalcCurMount();
}
else
{
if( res == 5 || res == 6 )
cur->request->status = WINIX_ERR_PERMISSION_DENIED;
else
cur->request->status = WINIX_ERR_NO_ITEM;
}
return ok;
}

154
core/system.h Executable file
View File

@@ -0,0 +1,154 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_system
#define headerfile_winix_core_system
#include <ctime>
#include "dirs.h"
#include "mounts.h"
#include "db/db.h"
#include "request.h"
#include "config.h"
#include "users.h"
#include "groups.h"
#include "rebus.h"
#include "loadavg.h"
#include "synchro.h"
#include "thumb.h"
#include "notify/notify.h"
// file system
class System
{
public:
// contains current directories tree
Dirs dirs;
// mount points
Mounts mounts;
// users
Users users;
// groups
Groups groups;
// rebus (captcha)
Rebus rebus;
// load averages
LoadAvg load_avg;
// notifications (by emails)
Notify notify;
// thumbnails (special thread)
Thumb thumb;
// the time when the winix starts
time_t system_start;
void SetCur(Cur * pcur);
void SetConfig(Config * pconfig);
void SetDb(Db * pdb);
void SetSynchro(Synchro * psynchro);
void Init();
void AddParams(const ParamTab & param_tab, std::wstring & str, bool clear_str = true);
void RedirectTo(const Item & item, const wchar_t * postfix = 0);
void RedirectTo(long item_id, const wchar_t * postfix = 0);
void RedirectTo(const std::wstring & url);
void RedirectWithFunctionAndParamsTo(const std::wstring & url);
void RedirectToLastDir();
void RedirectToLastItem(); // redirect to an item if exists or to the last directory
bool CanChangeUser(const Item & item, long new_user_id);
bool CanChangeGroup(const Item & item, long new_group_id);
bool CanChangePrivileges(const Item & item, int new_priv);
bool HasAccess(const Item & item, int mask);
bool HasReadAccess(const Item & item);
bool HasWriteAccess(const Item & item);
bool HasReadWriteAccess(const Item & item);
bool HasReadExecAccess(const Item & item);
bool HasReadExecAccessToPath(long dir_id);
bool HasReadExecAccessToPath(const std::vector<Item*> & dir_tab);
bool DirsHaveReadExecPerm();
void CheckAccessToItems(std::vector<Item> & item_tab);
bool CanUseHtml(long user_id);
bool CanUseBBCode(long user_id);
bool CanUseRaw(long user_id);
bool IsMemberOfGroup(long user_id, const wchar_t * group_name);
// creating item.file_path and item.file_fs (the mountpoint where the item is located)
bool CreateNewFile(Item & item);
bool MakeFilePath(const Item & item, std::wstring & path, bool thumb = false, bool create_dir = false, int chmod = 0755);
bool MakePath(const Item & item, std::wstring & path, bool clear_path = true);
Error AddFile(Item & item, int notify_code = 0);
Error EditFile(Item & item, bool with_url = true, int notify_code = 0);
// converting GMT time to local time (different for each user)
time_t LocalTime(time_t gmt_time);
tm LocalTime(const tm * ptm);
tm LocalTime(const tm & ptm);
int FollowLink(const std::vector<Item*> & current_dir_tab, const std::wstring & link_to,
std::vector<Item*> & out_dir_tab, Item & out_item);
int FollowAllLinks(const std::vector<Item*> & current_dir_tab, const std::wstring & link_to,
std::vector<Item*> & out_dir_tab, Item & out_item,
bool follow_dir_default = false, bool stop_on_link_redirect = false, bool check_access = true);
// starting from root dir
int FollowAllLinks(const std::wstring & link_to,
std::vector<Item*> & out_dir_tab, Item & out_item,
bool follow_dir_default = false, bool stop_on_link_redirect = false, bool check_access = true);
// using cur->request->dir_tab and cur->request->item
bool FollowAllLinks(const std::wstring & link_to,
bool follow_dir_default = false, bool stop_on_link_redirect = false, bool check_access = true);
private:
Cur * cur;
Db * db;
Config * config;
Synchro * synchro;
Item item_temp;
std::wstring link_to_temp, name_temp;
// for FollowAllLinks
std::vector<Item*> temp_follow_dir_tab;
std::vector<Item*> root_follow_dir_tab;
Item temp_follow_item;
bool CreateNewFileSimpleFs(Item & item);
bool CreateNewFileHashFs(Item & item);
bool FollowAllLinksDirFound(std::vector<Item*> & out_dir_tab,
bool follow_dir_default, bool stop_on_link_redirect, bool check_access);
bool FollowAllLinksFileOrSymlinkFound(std::vector<Item*> & out_dir_tab, Item & out_item,
bool stop_on_link_redirect, bool check_access);
};
#endif

View File

@@ -1,542 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#include "templates.h"
namespace TemplatesFunctions
{
Pattern pat_index;
Pattern pat_item;
Pattern pat_dir;
Pattern pat_item_add_edit;
Pattern pat_item_del_confirm;
Pattern pat_err_404;
Pattern pat_err_internal;
Functions functions;
void language(Info & i)
{
// at the moment only Polish language
i.out << "pl";
}
void title(Info & i)
{
i.out << "";
}
void charset(Info & i)
{
i.out << "iso-8859-2";
}
void version_major(Info & i)
{
i.out << MAJOR_VER;
}
void version_minor(Info & i)
{
i.out << MINOR_VER;
}
void version_revision(Info & i)
{
i.out << REVISION_VER;
}
void content(Info & i)
{
Pattern * p;
switch( request.result )
{
case Request::add_item:
case Request::edit_item:
p = &pat_item_add_edit;
break;
case Request::show_dir:
p = &pat_dir;
break;
case Request::show_item:
p = &pat_item;
break;
case Request::del_item_confirm:
p = &pat_item_del_confirm;
break;
case Request::err_internal:
p = &pat_err_internal;
break;
case Request::err404:
default:
p = &pat_err_404;
}
Generator gen(i.out, *p, functions);
gen.Generate();
}
void base_url(Info & i)
{
i.out << data.base_url;
}
void current_url(Info & i)
{
if( request.env_request_uri )
i.out << request.env_request_uri;
else
base_url(i);
}
void user_logged(Info & i)
{
i.result = request.session->is_logged;
}
void user(Info & i)
{
i.out << request.session->user;
}
void item_id(Info & i)
{
i.out << request.item.id;
}
void item_subject(Info & i)
{
i.out << HtmlSpecial(request.item.subject);
}
void item_content(Info & i)
{
//i.out << HtmlSpecial(request.item.content);
i.out << request.item.content;
}
void item_url_subject(Info & i)
{
i.out << request.item.url_subject;
}
void item_dir(Info & i)
{
std::string path;
if( data.dir.MakePath(request.item.parent_id, path) )
{
i.out << path;
}
else
{
i.out << "problem with generating a path";
}
}
// ---------
void old_item_id(Info & i)
{
i.out << request.session->item.id;
}
void old_item_subject(Info & i)
{
i.out << HtmlSpecial(request.session->item.subject);
}
void old_item_content(Info & i)
{
//i.out << HtmlSpecial(request.session->item.content);
i.out << request.session->item.content;
}
void old_item_url_subject(Info & i)
{
i.out << request.session->item.url_subject;
}
void old_item_dir(Info & i)
{
std::string path;
if( data.dir.MakePath(request.session->item.parent_id, path) )
{
i.out << path;
}
else
{
i.out << "problem with generating a path";
}
}
// ----
void full_dir(Info & i)
{
std::vector<Item>::size_type a;
for(a=0 ; a<request.cur_dir_table.size() ; ++a)
{
i.out << request.cur_dir_table[a].url_subject << '/';
}
}
std::vector<Item>::size_type item_index, dir_index;
void dir_items(Info & i)
{
if( i.iter >= (int)request.dir_table.size() )
{
i.result = false;
}
else
{
i.result = true;
dir_index = i.iter;
}
}
void dir_subject2(Info & i)
{
if( dir_index < request.dir_table.size() )
{
if( request.dir_table[dir_index].subject.empty() )
i.out << "bez nazwy";
else
HtmlSpecial(i.out, request.dir_table[dir_index].subject);
}
}
void dir_url_subject2(Info & i)
{
if( dir_index < request.dir_table.size() )
{
HtmlSpecial(i.out, request.dir_table[dir_index].url_subject);
}
}
void items(Info & i) // zamienic na fitems !!
{
if( i.iter >= (int)request.item_table.size() )
{
i.result = false;
}
else
{
i.result = true;
item_index = i.iter;
}
}
void item_subject2(Info & i)
{
if( item_index < request.item_table.size() )
{
if( request.item_table[item_index].subject.empty() )
i.out << "bez nazwy";
else
HtmlSpecial(i.out, request.item_table[item_index].subject);
}
}
void item_url_subject2(Info & i)
{
if( item_index < request.item_table.size() )
HtmlSpecial(i.out, request.item_table[item_index].url_subject);
}
void item_content2(Info & i)
{
if( item_index < request.item_table.size() )
//HtmlSpecial(i.out, request.item_table[item_index].content);
i.out << request.item_table[item_index].content;
}
void item_id2(Info & i)
{
if( item_index < request.item_table.size() )
i.out << request.item_table[item_index].id;
}
void incorrect_dir(Info & i)
{
if( request.session->done_status == Error::incorrect_dir )
i.result = true;
else
i.result = false;
}
std::vector<Item>::size_type current_dir_index;
void fcurrent_dir(Info & i)
{
if( i.iter < (int)request.cur_dir_table.size() )
{
current_dir_index = i.iter;
i.result = true;
}
else
i.result = false;
}
void current_dir_part_name(Info & i)
{
if( current_dir_index < request.cur_dir_table.size() )
i.out << request.cur_dir_table[current_dir_index].subject;
}
void current_dir_part_url(Info & i)
{
std::vector<Item>::size_type a;
i.out << data.base_url;
for(a = 0 ; a <= current_dir_index && a < request.cur_dir_table.size() ; ++a)
{
i.out << request.cur_dir_table[a].url_subject << '/';
}
}
void edit_item(Info & i)
{
i.result = request.result == Request::edit_item;
}
void added_item(Info &i)
{
i.result = request.session->done == Done::added_item;
}
void edited_item(Info &i)
{
i.result = request.session->done == Done::edited_item;
}
void deleted_item(Info &i)
{
i.result = request.session->done == Done::deleted_item;
}
// zostawic tylko jedna funkcje done_with_errors (bedzie uzywana do roznych celow) !!
void deleted_item_errors(Info & i)
{
i.result = request.session->done_status != Error::ok;
}
void done_with_errors(Info & i)
{
i.result = request.session->done_status != Error::ok;
}
void done_status(Info & i)
{
i.out << static_cast<int>( request.session->done_status );
}
void fitems_in_dir(Info & i)
{
// i.out << "abc: " << variables["fitems_directory"];
}
void loggedout(Info & i)
{
i.result = request.session->done == Done::loggedout;
}
} // namespace TemplatesFunctions
void Templates::CreateFunctions()
{
using namespace TemplatesFunctions;
functions.Clear();
functions.Insert("language", language);
functions.Insert("title", title);
functions.Insert("charset", charset);
functions.Insert("content", content);
functions.Insert("version_major", version_major);
functions.Insert("version_minor", version_minor);
functions.Insert("version_revision", version_revision);
functions.Insert("base_url", base_url);
functions.Insert("current_url", current_url);
functions.Insert("user_logged", user_logged);
functions.Insert("user", user);
functions.Insert("item_id", item_id);
functions.Insert("item_subject", item_subject);
functions.Insert("item_content", item_content);
functions.Insert("item_url_subject", item_url_subject);
functions.Insert("item_dir", item_dir);
functions.Insert("old_item_id", old_item_id);
functions.Insert("old_item_subject", old_item_subject);
functions.Insert("old_item_content", old_item_content);
functions.Insert("old_item_url_subject", old_item_url_subject);
functions.Insert("old_item_dir", old_item_dir);
functions.Insert("dir_items", dir_items);
functions.Insert("items", items);
functions.Insert("item_subject2", item_subject2);
functions.Insert("dir_subject2", dir_subject2);
functions.Insert("full_dir", full_dir);
functions.Insert("dir_url_subject2", dir_url_subject2);
functions.Insert("item_url_subject2", item_url_subject2);
functions.Insert("item_content2", item_content2);
functions.Insert("item_id2", item_id2);
functions.Insert("edit_item", edit_item);
functions.Insert("incorrect_dir", incorrect_dir);
functions.Insert("fcurrent_dir", fcurrent_dir);
functions.Insert("current_dir_part_name", current_dir_part_name);
functions.Insert("current_dir_part_url", current_dir_part_url);
functions.Insert("added_item", added_item);
functions.Insert("edited_item", edited_item);
functions.Insert("deleted_item", deleted_item);
functions.Insert("loggedout", loggedout);
functions.Insert("deleted_item_errors", deleted_item_errors);
functions.Insert("done_with_errors", done_with_errors);
functions.Insert("done_status", done_status);
functions.Insert("fitems_in_dir", fitems_in_dir);
}
void Templates::Read()
{
using namespace TemplatesFunctions;
pat_index.Directory(data.templates);
pat_index.ParseFile(data.default_index);
pat_item.Directory(data.templates);
pat_item.ParseFile("item.html");
pat_dir.Directory(data.templates);
pat_dir.ParseFile("dir.html");
pat_item_add_edit.Directory(data.templates);
pat_item_add_edit.ParseFile("item_add_edit.html");
pat_err_404.Directory(data.templates);
pat_err_404.ParseFile("err_404.html");
pat_item_del_confirm.Directory(data.templates);
pat_item_del_confirm.ParseFile("item_del_confirm.html");
pat_err_internal.Directory(data.templates);
pat_err_internal.ParseFile("err_internal.html");
CreateFunctions();
}
void Templates::Generate()
{
using namespace TemplatesFunctions;
// clear some variables (indexes for example)
item_index = 0;
current_dir_index = 0;
Generator generator(request.page, pat_index, functions);
generator.Generate();
}

View File

@@ -1,44 +0,0 @@
/*
* This file is a part of CMSLU -- Content Management System like Unix
* and is not publicly distributed
*
* Copyright (c) 2008, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfiletemplates
#define headerfiletemplates
#include "../../ezc/src/ezc.h"
#include "data.h"
#include "request.h"
#include "item.h"
#include "db.h"
#include "error.h"
using namespace Ezc;
class Templates
{
public:
void Read();
void Generate();
void CreateFunctions();
};
#endif

13
core/textstream.cpp Executable file
View File

@@ -0,0 +1,13 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "textstream.h"
#include "misc.h"

296
core/textstream.h Executable file
View File

@@ -0,0 +1,296 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_textstream
#define headerfile_winix_core_textstream
#include <string>
#include "misc.h"
/*
a special class representing a stream buffer
similar to std::ostringstream
StringType can be either std::string or std::wstring
this class doesn't use UTF-8 in any kind
*/
template<class StringType>
class TextStream
{
public:
typedef typename StringType::value_type CharType;
typedef typename StringType::value_type char_type;
void Clear();
bool Empty() const;
size_t Size() const;
void Reserve(size_t len);
const StringType & Str() const;
const CharType * CStr() const;
TextStream & operator<<(const char * str);
TextStream & operator<<(const std::string * str);
TextStream & operator<<(const std::string & str);
TextStream & operator<<(const wchar_t * str);
TextStream & operator<<(const std::wstring * str);
TextStream & operator<<(const std::wstring & str);
TextStream & operator<<(char);
TextStream & operator<<(wchar_t);
TextStream & operator<<(int);
TextStream & operator<<(long);
TextStream & operator<<(unsigned int);
TextStream & operator<<(unsigned long);
TextStream & operator<<(double);
TextStream & operator<<(const void *);// printing a pointer
TextStream & Write(const char * buf, size_t len);
TextStream & Write(const wchar_t * buf, size_t len);
TextStream & write(const char * buf, size_t len); // for compatibility with standard library (Ezc uses it)
TextStream & write(const wchar_t * buf, size_t len);
protected:
StringType buffer;
};
template<class StringType>
void TextStream<StringType>::Clear()
{
buffer.clear();
}
template<class StringType>
bool TextStream<StringType>::Empty() const
{
return buffer.empty();
}
template<class StringType>
size_t TextStream<StringType>::Size() const
{
return buffer.size();
}
template<class StringType>
void TextStream<StringType>::Reserve(size_t len)
{
buffer.reserve(len);
}
template<class StringType>
const StringType & TextStream<StringType>::Str() const
{
return buffer;
}
template<class StringType>
const typename TextStream<StringType>::CharType * TextStream<StringType>::CStr() const
{
return buffer.c_str();
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(const char * str)
{
AssignString(str, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(const std::string * str)
{
AssignString(*str, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(const std::string & str)
{
AssignString(str, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(const wchar_t * str)
{
AssignString(str, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(const std::wstring * str)
{
AssignString(*str, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(const std::wstring & str)
{
AssignString(str, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(char v)
{
buffer += v;
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(wchar_t v)
{
buffer += static_cast<CharType>(v);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(int v)
{
wchar_t buf[50];
size_t len = sizeof(buf) / sizeof(wchar_t);
Toa(v, buf, len);
AssignString(buf, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(long v)
{
wchar_t buf[50];
size_t len = sizeof(buf) / sizeof(wchar_t);
Toa(v, buf, len);
AssignString(buf, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(unsigned int v)
{
wchar_t buf[50];
size_t len = sizeof(buf) / sizeof(wchar_t);
Toa(v, buf, len);
AssignString(buf, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(unsigned long v)
{
wchar_t buf[50];
size_t len = sizeof(buf) / sizeof(wchar_t);
Toa(v, buf, len);
AssignString(buf, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(double v)
{
char buf[50];
sprintf(buf, "%f", v);
AssignString(buf, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::operator<<(const void * v)
{
wchar_t buf[50];
size_t len = sizeof(buf) / sizeof(wchar_t);
buf[0] = '0';
buf[1] = 'x';
Toa(reinterpret_cast<unsigned long>(v), buf+2, len-2, 16);
AssignString(buf, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::Write(const char * buf, size_t len)
{
AssignString(buf, len, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::write(const char * buf, size_t len)
{
return Write(buf, len);
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::Write(const wchar_t * buf, size_t len)
{
AssignString(buf, len, buffer, false);
return *this;
}
template<class StringType>
TextStream<StringType> & TextStream<StringType>::write(const wchar_t * buf, size_t len)
{
return Write(buf, len);
}
#endif

309
core/thumb.cpp Executable file
View File

@@ -0,0 +1,309 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#include <ctime>
#include "thumb.h"
#include "utf8.h"
#include "log.h"
#include "system.h"
void Thumb::SetDb(Db * pdb)
{
db = pdb;
}
void Thumb::SetConfig(Config * pconfig)
{
config = pconfig;
}
void Thumb::SetSystem(System * psystem)
{
system = psystem;
}
// first thread (objects locked)
void Thumb::CreateThumb(const Item & item, size_t cx, size_t cy, int aspect_mode)
{
item_temp.file = item;
item_temp.cx = cx;
item_temp.cy = cy;
item_temp.aspect_mode = aspect_mode;
thumb_tab.insert(thumb_tab.end(), item_temp);
WakeUpThread();
}
// second thread (objects locked)
bool Thumb::SignalReceived()
{
return !thumb_tab.empty();
}
// second thread (objects not locked)
void Thumb::Do()
{
ThumbTab::iterator i;
bool end;
Lock();
i = thumb_tab.begin();
Unlock();
do
{
Lock();
if( i != thumb_tab.end() )
{
item_work = *i;
thumb_tab.erase(i++);
end = false;
}
else
{
end = true;
}
Unlock();
if( !end )
CreateThumbnail();
}
while( !end && !IsExitSignal() );
}
void Thumb::EscapePath(const std::string & path)
{
command << '"';
for(size_t i=0 ; i<path.size() ; ++i)
{
if( path[i] == '"' )
command << '\\';
command << path[i];
}
command << "\" ";
}
/*
from: http://www.imagemagick.org/script/command-line-processing.php#geometry
scale% Height and width both scaled by specified percentage.
scale-x%xscale-y% Height and width individually scaled by specified percentages. (Only one % symbol needed.)
width Width given, height automagically selected to preserve aspect ratio.
xheight Height given, width automagically selected to preserve aspect ratio.
widthxheight Maximum values of height and width given, aspect ratio preserved.
widthxheight^ Minimum values of width and height given, aspect ratio preserved.
widthxheight! Width and height emphatically given, original aspect ratio ignored.
widthxheight> Change as per widthxheight but only if an image dimension exceeds a specified dimension.
widthxheight< Change dimensions only if both image dimensions exceed specified dimensions.
*/
void Thumb::SelectAspect()
{
switch( item_work.aspect_mode )
{
case WINIX_THUMB_MODE_1:
command << item_work.cx;
break;
case WINIX_THUMB_MODE_3:
command << item_work.cx << "x" << item_work.cy;
break;
case WINIX_THUMB_MODE_4:
command << '"' << item_work.cx << "x" << item_work.cy << "^\"";
break;
case WINIX_THUMB_MODE_5:
command << '"' << item_work.cx << "x" << item_work.cy << "!\"";
break;
case WINIX_THUMB_MODE_6:
command << '"' << item_work.cx << "x" << item_work.cy << ">\"";
break;
case WINIX_THUMB_MODE_7:
command << '"' << item_work.cx << "x" << item_work.cy << "<\"";
break;
case WINIX_THUMB_MODE_2:
default:
command << "x" << item_work.cy;
break;
}
}
// second thread (objects are not locked)
bool Thumb::CreateCommand()
{
bool res;
command.Clear();
stream_tmp_path.Clear();
Lock();
Ezc::WideToUTF8(config->convert_cmd, tempa);
command << tempa << " -quiet -strip -thumbnail ";
SelectAspect();
command << " ";
if( system->MakeFilePath(item_work.file, src_path) )
{
Ezc::WideToUTF8(src_path, tempa);
EscapePath(tempa);
stream_tmp_path << config->upload_dir << L"/tmp/thumb_" << std::time(0);
Ezc::WideToUTF8(stream_tmp_path.Str(), string_tmp_patha);
EscapePath(string_tmp_patha);
res = true;
}
else
{
log << log1 << "Thumb: cannot create a source path" << logend;
res = false;
}
Unlock();
return res;
}
// second thread (objects are not locked)
void Thumb::SaveTmpThumbnail()
{
bool moved = false;
Lock();
// the file could have been changed especially when creating thumbnail lasted too long
iq.SetAll(false, false);
iq.sel_parent_id = true;
iq.sel_file = true;
iq.sel_url = true;
iq.sel_type = true;
iq.WhereId(item_work.file.id);
if( db->GetItem(item_work.file, iq) == WINIX_ERR_OK )
{
if( system->MakeFilePath(item_work.file, dst_path, true, true, config->upload_dirs_chmod) )
{
if( RenameFile(stream_tmp_path.Str(), dst_path) )
{
log << log3 << "Thumb: created a thumbnail: " << dst_path << logend;
db->EditHasThumbById(true, item_work.file.id);
moved = true;
}
else
{
log << log1 << "Thumb: cannot move a temporary file: " << stream_tmp_path.Str() << ", to: " << dst_path << logend;
}
}
else
{
log << log1 << "Thumb: cannot create a destination path" << logend;
}
}
if( !moved )
::RemoveFile(stream_tmp_path.Str());
Unlock();
}
// second thread (objects are not locked)
void Thumb::CreateThumbnail()
{
if( !CreateCommand() )
return;
int res = std::system(command.CStr());
if( res == 0 )
{
SaveTmpThumbnail();
}
else
{
Lock();
log << log3 << "Thumb: some problems with creating a thumbnail " << tempa
<< ", 'convert' process returned: " << res << logend;
Unlock();
}
}
// second thread (objects are not locked)
// !! there is a problem with GIF files
// Bus error (core dumped)
/*
#include "wand/MagickWand.h"
// compiler options:
// include: -I/usr/local/include/ImageMagick
// link with: `MagickWand-config --ldflags --libs`
void Thumb::CreateThumbnail()
{
Ezc::WideToUTF8(item_work.source, sourcea);
Ezc::WideToUTF8(item_work.dst, dsta);
MagickWandGenesis();
MagickWand * wand = NewMagickWand();
if( MagickReadImage(wand, sourcea.c_str()) )
{
MagickThumbnailImage(wand, item_work.cx, item_work.cy);
if( MagickWriteImage(wand, dsta.c_str()) )
{
Lock();
log << log3 << "Thumb: created a thumbnail: " << dsta << logend;
Unlock();
}
}
DestroyMagickWand(wand);
MagickWandTerminus();
}
*/

97
core/thumb.h Executable file
View File

@@ -0,0 +1,97 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_thumb
#define headerfile_winix_core_thumb
#include <string>
#include <list>
#include "basethread.h"
#include "textstream.h"
#include "db/db.h"
#include "core/item.h"
#include "core/config.h"
class System;
// Width given, height automagically selected to preserve aspect ratio.
#define WINIX_THUMB_MODE_1 1
// Height given, width automagically selected to preserve aspect ratio.
#define WINIX_THUMB_MODE_2 2
// Maximum values of height and width given, aspect ratio preserved.
#define WINIX_THUMB_MODE_3 3
// Minimum values of width and height given, aspect ratio preserved.
#define WINIX_THUMB_MODE_4 4
// Width and height emphatically given, original aspect ratio ignored.
#define WINIX_THUMB_MODE_5 5
// Change as per widthxheight but only if an image dimension exceeds a specified dimension.
#define WINIX_THUMB_MODE_6 6
// Change dimensions only if both image dimensions are less than specified dimensions.
#define WINIX_THUMB_MODE_7 7
class Thumb : public BaseThread
{
public:
void CreateThumb(const Item & item, size_t cx, size_t cy, int aspect_mode);
void SetDb(Db * pdb);
void SetConfig(Config * pconfig);
void SetSystem(System * psystem);
private:
Db * db;
Config * config;
System * system;
struct ThumbItem
{
Item file;
size_t cx;
size_t cy;
int aspect_mode;
};
// queue of thumbnails to create
typedef std::list<ThumbItem> ThumbTab;
ThumbTab thumb_tab;
ThumbItem item_temp;
// only for second thread
ThumbItem item_work;
std::wstring src_path, dst_path;
std::string tempa, string_tmp_patha;
TextStream<std::string> command;
TextStream<std::wstring> stream_tmp_path;
DbItemQuery iq;
virtual bool SignalReceived();
virtual void Do();
bool CreateCommand();
void SaveTmpThumbnail();
void CreateThumbnail();
void SelectAspect();
void EscapePath(const std::string & path);
};
#endif

223
core/ugcontainer.h Executable file
View File

@@ -0,0 +1,223 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_ugcontainer
#define headerfile_winix_core_ugcontainer
#include <vector>
#include <map>
#include <stdexcept>
#include "log.h"
template<class Type>
class UGContainer
{
public:
typedef typename std::vector<Type> Table;
typedef typename Table::iterator Iterator;
typedef typename Table::size_type SizeType;
typedef typename std::map<long, SizeType> TableId;
typedef typename std::map<std::wstring, SizeType> TableName;
UGContainer();
Iterator Begin();
Iterator End();
SizeType Size();
bool Empty();
Iterator PushBack(const Type & type); // can return End() if the user already exists
void Clear();
bool Is(long id);
bool Is(const std::wstring & name);
Iterator FindId(long id);
Iterator FindName(const std::wstring & name);
Type & operator[](SizeType pos);
private:
void AddIndexes(SizeType pos);
void RebuildIndexes();
// main table
Table table;
// indexes
TableId table_id;
TableName table_name;
};
template<class Type>
UGContainer<Type>::UGContainer() // : table(100)
{
}
template<class Type>
typename UGContainer<Type>::Iterator UGContainer<Type>::Begin()
{
return table.begin();
}
template<class Type>
typename UGContainer<Type>::Iterator UGContainer<Type>::End()
{
return table.end();
}
template<class Type>
typename UGContainer<Type>::SizeType UGContainer<Type>::Size()
{
return table.size();
}
template<class Type>
bool UGContainer<Type>::Empty()
{
return table.empty();
}
template<class Type>
typename UGContainer<Type>::Iterator UGContainer<Type>::PushBack(const Type & type)
{
if( Is(type.id) || Is(type.name) )
return End();
table.push_back(type);
log << log2 << "UGCont: added, id: " << type.id << ", name: " << type.name << logend;
AddIndexes( table.size() - 1 );
return --table.end();
}
template<class Type>
void UGContainer<Type>::Clear()
{
table.clear();
table_id.clear();
table_name.clear();
}
template<class Type>
bool UGContainer<Type>::Is(long id)
{
typename TableId::iterator i = table_id.find(id);
if( i == table_id.end() )
return false;
return true;
}
template<class Type>
bool UGContainer<Type>::Is(const std::wstring & name)
{
typename TableName::iterator i = table_name.find(name);
if( i == table_name.end() )
return false;
return true;
}
template<class Type>
typename UGContainer<Type>::Iterator UGContainer<Type>::FindId(long id)
{
typename TableId::iterator i = table_id.find(id);
if( i == table_id.end() )
return table.end();
return table.begin() + i->second;
}
template<class Type>
typename UGContainer<Type>::Iterator UGContainer<Type>::FindName(const std::wstring & name)
{
typename TableName::iterator i = table_name.find(name);
if( i == table_name.end() )
return table.end();
return table.begin() + i->second;
}
template<class Type>
void UGContainer<Type>::AddIndexes(UGContainer<Type>::SizeType pos)
{
table_id.insert( std::make_pair(table[pos].id, pos) );
table_name.insert( std::make_pair(table[pos].name, pos) );
log << log4 << "UGCont: added indexes to: id: " << table[pos].id << ", name: " << table[pos].name << logend;
}
template<class Type>
void UGContainer<Type>::RebuildIndexes()
{
log << log4 << "UGCont: rebuilding indexes" << logend;
table_id.clear();
table_name.clear();
SizeType i, len = table.size();
for(i=0 ; i!=len ; ++i)
AddIndexes( i );
log << log4 << "UGCont: indexes rebuilt, table.size: " << table.size() << ", table_id.size: "
<< table_id.size() << ", table_name.size: " << table_name.size() << logend;
}
template<class Type>
Type & UGContainer<Type>::operator[](UGContainer<Type>::SizeType pos)
{
if( pos >= table.size() )
throw std::out_of_range("UGContainer: operator[]: index is out of range");
return table[pos];
}
#endif

65
core/user.h Executable file
View File

@@ -0,0 +1,65 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_user
#define headerfile_winix_core_user
#include <string>
#include <vector>
struct User
{
long id;
std::wstring name;
bool super_user;
std::vector<long> groups;
std::wstring email;
int notify;
// !! currently all users have the same offset
// option in config: time_zone_offset
int time_zone_offset;
User()
{
Clear();
}
void Clear()
{
id = -1;
name.clear();
super_user = false;
groups.clear();
email.clear();
notify = 0;
time_zone_offset = 0;
}
bool IsMemberOf(long group)
{
std::vector<long>::iterator i;
for(i=groups.begin() ; i!=groups.end() ; ++i)
if( *i == group )
return true;
return false;
}
};
#endif

191
core/users.cpp Executable file
View File

@@ -0,0 +1,191 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include <arpa/inet.h>
#include "users.h"
Users::Users()
{
how_many_logged = 0;
Clear();
}
void Users::SetCur(Cur * pcur)
{
cur = pcur;
}
void Users::Clear()
{
table.Clear();
}
void Users::ReadUsers(Db * db)
{
Clear();
db->GetUsers(table);
}
void Users::SetTimeZoneOffset(int offset)
{
Table::Iterator i;
for(i=table.Begin() ; i!=table.End() ; ++i)
{
i->time_zone_offset = offset;
}
}
bool Users::AddUser(const User & user)
{
Table::Iterator i = table.PushBack(user);
return (i != table.End());
}
bool Users::IsUser(const std::wstring & name)
{
return table.Is(name);
}
User * Users::GetUser(long user_id)
{
Table::Iterator i = table.FindId(user_id);
if( i == table.End() )
return 0;
return &(*i);
}
User * Users::GetUser(const std::wstring & name)
{
Table::Iterator i = table.FindName(name);
if( i == table.End() )
return 0;
return &(*i);
}
long Users::GetUserId(const std::wstring & name)
{
User * puser = GetUser(name);
if( !puser )
return -1;
return puser->id;
}
Users::Iterator Users::Begin()
{
return table.Begin();
}
Users::Iterator Users::End()
{
return table.End();
}
Users::SizeType Users::Size()
{
return table.Size();
}
User & Users::operator[](Users::SizeType pos)
{
return table[pos];
}
void Users::LoginUser(long user_id, bool remember_me)
{
if( !cur->session )
return;
if( cur->session->id == 0 )
{
log << log1 << "Users: cannot login a user on a temporary session" << logend;
return;
}
cur->session->puser = GetUser(user_id);
cur->session->spam_score = 0;
if( !cur->session->puser )
{
log << log1 << "Users: user id: " << user_id << " is not in system.users table" << logend;
return;
}
cur->session->remember_me = remember_me;
last.UserLogin(user_id, cur->session->puser->name, inet_addr(cur->request->env_remote_addr), cur->session->id);
how_many_logged += 1;
log << log2 << "User " << cur->session->puser->name << " (id: " << user_id << ") logged" << logend;
}
void Users::LogoutCurrentUser()
{
if( !cur->session || !cur->session->puser )
return;
log << log2 << "Users: user " << cur->session->puser->name << ", id: "
<< cur->session->puser->id << " logged out" << logend;
last.UserLogout(cur->session->puser->id, cur->session->id);
if( how_many_logged > 0 ) // for safety
how_many_logged -= 1;
cur->session->puser = 0;
cur->session->remember_me = 0;
}
void Users::IncrementLoggedUsers()
{
how_many_logged += 1;
}
long Users::HowManyLogged()
{
return how_many_logged;
}

67
core/users.h Executable file
View File

@@ -0,0 +1,67 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_users
#define headerfile_winix_core_users
#include <map>
#include "user.h"
#include "ugcontainer.h"
#include "lastcontainer.h"
#include "cur.h"
#include "db/db.h"
class Users
{
typedef UGContainer<User> Table;
Table table;
Cur * cur;
long how_many_logged;
public:
typedef Table::Iterator Iterator;
typedef Table::SizeType SizeType;
LastContainer last;
Users();
void SetCur(Cur * pcur);
void Clear();
void ReadUsers(Db * db);
void SetTimeZoneOffset(int offset); // !! temporarily one time_zone for all users
bool AddUser(const User & user);
bool IsUser(const std::wstring & name);
User * GetUser(long user_id);
User * GetUser(const std::wstring & name);
long GetUserId(const std::wstring & name);
Iterator Begin();
Iterator End();
SizeType Size();
User & operator[](SizeType pos);
void LoginUser(long user_id, bool remember_me);
void LogoutCurrentUser();
void IncrementLoggedUsers();
long HowManyLogged();
};
#endif

19
core/version.h Executable file
View File

@@ -0,0 +1,19 @@
/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#ifndef headerfile_winix_core_version
#define headerfile_winix_core_version
#define WINIX_VER_MAJOR 0
#define WINIX_VER_MINOR 4
#define WINIX_VER_REVISION 6
#endif

Some files were not shown because too many files have changed in this diff Show More