Commit Diff


commit - 0cc8edab99deae5a987db984e957b733a51816ba
commit + 7dc1039c56f1f1a35707aea31b6bf10028f6c20e
blob - /dev/null
blob + 100bf7c26d33a82dcded3ac21b6f353f7c25cfbc (mode 644)
--- /dev/null
+++ ChangeLog.txt
@@ -0,0 +1,531 @@
+04.10.2001 - 06.10.2001
+Code cleanup in dbase.cpp: completly rewrite code for using CFreeDB class,
+changed semaphores to file locks (*nix only), now it can be compiled in Win32
+(however, without flock())
+
+06.10.2001 - 07.10.2001
+Added nested tags support, some cleanup in boardtags.cpp code.
+Fixed logoff disappearing in lite version 1.0.
+
+11.10.2001 - 13.10.2001
+Fixed some bugs: in boardtags.cpp bug with right parsing invalid smile code (in strcat_ParseSmiles()),
+in dbase.cpp memory leaks with body of the message (now body addressed as char**) and bug with  fwrite() at the end of file.
+Also added some interface strings in design.h.
+
+14.10.2001
+Added Webbbs to WWWConf convertor to project.
+
+20.10.2001
+Added change message support.
+
+27.10.2001
+Fixed some bugs in Webbbs convertor, and add links and images support.
+Also fixed bug with very long words in reindex.cpp.
+
+28.10.2001
+Some perfomance optimization in indexer.cpp (removed word check and dynamic memory allocation).
+Added cached indexes.
+
+16.11.2001
+Session ID now will be stored throught cookie.
+
+20.11.2001
+Added Fsize support throught Win32 functions under WIN32.
+
+15.12.2001
+Fixed bug in message editing...
+
+19.02.2002
+Change way for logging in error.cpp, now it support formats and variable count
+of variables. Also added support for loggin exact point where printhtmlerror()
+was called.
+
+12.03.2002
+Added topic support.
+
+27.04.2002
+Changed the way of generation session id. Now it use other way of random generation based statistic algorithm.
+
+28.04.2002
+Fixed bug in indexer.cpp, have a stable version now.
+
+01.05.2002
+Added anti-spam for read counter.
+
+17.06.2002  СДЕЛАТЬ следить за темой (тредом) !!! запоминать темы за которыми нужно следить в профайле пользователя !!!
+максимум до 10-20 тем.
+
+24.10.2002
+Fixed bug with nested tags (buffer overflow and stack corruption if more than 8 nested tags was in the message).
+
+25.10.2002
+
+03.11.2002
+Removed username/password from the post message form for the registred users.
+
+06.11.2002
+Global changes in user profile storing (profiles.cpp now use hashindex instead of common indexer), some code cleanup.
+Added hashindex.cpp/hashindex.h.
+
+07.11.2002
+Fixed support of Win32 platform: added R/W file locking. Some code cleanup.
+
+08.11.2002
+Fixed problem with preview.
+Message storing format was changed - now all messages saved after preparse with native WWWConf tags (w/o convertion to HTML).
+ParseBoardTags also have preparse and enter convertion ability now.
+
+10.11.2002
+First topic (by number) int the thread will not be showed (we assume that it's default topic).
+
+11.11.2002
+Added support for email ackn.
+
+12.11.2002
+Automatic logon after registration.
+
+18.11.2002
+Fixed bug in hashindex.cpp (right storing strings with same hash index).
+
+29.11.2002
+Fixed bug with compilation with TOPICS_SYSTEM_SUPPORT == 0.
+
+01.12.2002
+A lot of small fixes, including webbbs convertor (work with indigo).
+
+03.12.2002
+Added new security value for the user - SecHeader. Changed profile format (transparently, because of decrementing PASSWORD length by 1).
+Fixed problem with preview and quoted text.
+Added incremental indexing.
+New version b17.
+Russian nicknames will now be allowed
+Added Makefile for bbsconv
+
+04.12.2002
+Microfix for the long profile name viewing.
+Added stopindex to indexer.
+Added autologin checkbox to the message form when posting as unregistred user.
+
+05.12.2002
+Added user name info while posting as logged in user.
+Merge with aleczander - topbanner and bottombanner can be compiled as defines now, added USE_TEXT_BOTTOMBANNER and USE_TEXT_TOPBANNER defines.
+Start working with CSS re-design.
+
+7.12.2002
+Added additional view - only headers of thread.
+
+9.12.2002
+Added IPaddress to Message structure (transparently, because of decrementing HOSTNAME string length by 4).
+Fixed bug in incremental reindexer (reindex.cpp).
+Check and fix for "message w/o body" symbol at the end of the message header.
+Started work with USER_PROFILES_SUPPORT define (not completed yet).
+Returned email ackn. check box while posting as unreg. user.
+
+10.12.2002
+Some perfomance relative changes in bbsconv.
+
+12.12.2002
+Changed the way of signature interpretation in empty messages. Signature will be ignored from now.
+Added reference to posted message in "post complete" message.
+Fixed little bug in hostname resolve if strlen of hostname == 0.
+Fixed little bug - title in browser incorrectly displayed after configure.
+
+17.12.2002
+Fixed problem with "+" through cookie w/o expiration time.
+Added "To Message" when viewing large threads.
+New version b18.
+
+18.12.2002
+Fixed small bug with +.
+Do not allow name, header or body of the message containing spaces only.
+Fixed possible buffer overflow with long host names.
+Fixed some memory leaks.
+Fixed topic dissapearing during message preview.
+
+19.12.2002
+Fixed problem with repeating No-message tag in the message (will be deleted from now).
+Added message about index viewing style (Merges with aleczander).
+Some fixes connected with css support (Merges with aleczander).
+Added define for turn off locale setting (Merges with aleczander).
+
+20.12.2002
+Some fixes in logins.cpp (large session count problem).
+ResetNew implemented as redirect now.
+Added POST_ALLOW_UNDER_SAME_NICK define to allow modify behaviour of the board.
+Fixed bug with AuthorName and Subject length.
+
+21.12.2002
+Fixed bug with nick names with spec. symbols.
+Configure now will redirect to index page.
+Fixed little bug in configuration form.
+
+22.12.2002
+Enabled email ackn (seems that it works).
+
+24.12.2002, alec
+Added second bar with static links.
+Partially fixed bug 'returning to index from rolled thread'.
+
+26.12.2002, alec
+Added email printing to profman -v.
+
+29.12.2002
+Fixed memory damage in cookies.
+Changed the way working with message flags during message post - now parent flags MESSAGE_IS_INVISIBLE, MESSAGE_COLLAPSED_THREAD and MESSAGE_IS_CLOSED will be applyed to child message too. It also completely fixed bug 'returning to index from rolled thread'.
+Added lost password form.
+
+30.12.2002, alec
+Translatation of email messages, acknowledgw and password retrival
+Fixed in-thread navigation (MESSAGEHEAD_to_message link was broken in rolled threads).
+Now we allow to post to the last 15k messages only.
+Added logging for admin tasks: close, roll, hide, delete.
+
+03.01.2003, www
+Fixed ***very important*** bug connected with absence fflush() call before unlock file. It could lead to database corruption.
+
+05.01.2003, www
+Changed interpretation of ban rules... added allow and deny rules
+
+07.01.2003, www
+Fixed bug with several collapsed threads going one after another.
+New messages will be marked in collapsed threads too.
+New version b19.
+
+11.01.2003, alec
+Added new topic, links...
+
+12.01.2003, www
+Added last user IP in user information structure in profile (visible only to admin).
+Changed the way of interpretation of last login date of user. It's last access date now and updated after every access of the user.
+Fixed bugs with showing several invisible and collapsed threads going one after another.
+Added IP of poster in message view for administrator.
+
+13.01.2003, www
+Added updating date and last IP address during posting as registred user.
+Fixed bug with invisible threads corrupting message index for common users.
+
+14.01.2003, alec
+Partially translated faq-help.html, fixed rules.html, authors.html.
+Added link to rules.html to links bar.
+
+16.01.2003, www
+Fixed bug (added 13.01.2003) with several collapsed thread going one after another.
+
+19.01.2003, www
+Added pages to the search result.
+
+20.01.2003, www
+Fixed problem connected with navigation problem to index when posting to the rolled thread.
+
+21.01.2003, www
+Fixed problem showing collapsed thread when topic filter active.
+Added modification to the profile system, added user status.
+Added user modification form to the profile view (for admin).
+
+22.01.2003, alec
+Moved from DL+DD to DIV+BR, div2.diff + board.css patching
+Removed first style of viewing, MESSAGEHEAD_configure_showhronforward (div3.diff)
+
+22.01.2003, www
+Added printing new message count in collapsed thread.
+Disabled smile translation in PRE.
+
+23.01.2003, www
+Fixed little problem with new message count in collapsed thread.
+Added url autoparsing (expiremental). Very dirty code now.
+alec: DL+DD<->DIV+BR  autodetect for Links and Lynx useragents added (auto_dd.diff),
+      inserted board.css to messages.h
+alec: rewrited Makefile
+
+24.01.2003, www
+Fixed bug in url autoparsing.
+
+25.01.2003, www
+alec: New version of *nix makefile (support dependencies now).
+Added checking url flags during url autoparsing.
+In [url] tag parser added autoadding http:// if it not specified in url.
+
+26.01.2003, www
+Added quick topic modification.
+
+27.01.2003, alec
+changed ALLOW_MARK_NEW_MESSAGES  could be 1 or 2 now
+cosmetic changes, devold/cosmetic1.diff
+
+30.01.2003, alec
+* fixed bug: admin could not preview messages because of error in topic edit 
+  form (devold/admin_preview.diff)
+* fixed css, now works for mozilla (devold/css_fix.diff)
+
+31.01.2003, alec
+* added javascript for check/uncheck all topics
+* Mozilla/2.02 added to DL autodetect
+* HTML cleanup, all TH -> TD (what's TH ? :))
+* one patch: devold/java_checkall.diff 
+* fixed my bug in RT_REDIRECT, now /board/index.cgi?read=XX is redirecting
+  to /index.cgi?read=XX
+
+02.02.2003, www
+Fixed memory allocation bug in GenerateHashwordList() in hashindex.cpp.
+alec/www: Added sort modes in user list (currently: by name, by access date, by post count, by ip).
+Changed the way working with signatures, it will be added automatically to message w/o printing to form.
+patches: (userlist.diff, userlist2.diff)
+
+03.02.2003, www
+Minor fixes.
+Added user right modification by admin.
+New version b20.
+
+04.02.2003, alec
+* added Topics_List_map for listing Topics in desired order in forms(topics_map.diff)
+www: Fixed little bug with tag parsing like [hr].
+
+14.02.2003
+Added personal message support.
+
+18.02.2003, alec
+* simplified DB_Base::printhtmlmessage_in_index 
+* minor html changes in personal messages 
+* added target=_blank to search results
+
+21.02.2003
+Fixed new message dissapearing in resetnew command.
+
+23.02.2003
+Added history to personal messages.
+Link in messages will now be underlined.
+
+24.02.2003
+Fixed appearing url in message containing only pictures.
+
+25.02.2003
+Some bugs  fixed in personal messages (viewing).
+
+26.02.2003
+Fixed some little bugs in personal messages.
+
+01.03.2003
+Added private message manager to the project (prvman).
+
+02.03.2003
+Added announce support.
+In personal message added new error message "too long message".
+Added refresh count (incrementing every refresh) to the user profiles.
+
+03.03.2003
+Added sorting by refresh count to "all users".
+Added banner picture and 2-d link bar disable to configuration form.
+
+05.03.2003
+user right caching no longer supported.
+Added new smiles (from -=MC=-).
+
+06.03.2003
+Added announce hiding/showing trought cookies.
+
+07.03.2003
+Some interfaces and translation fixes.
+Removed prvman from project, all functionality moved to profman.
+Fixed little bug in header of brower (cutting tags was incorrect).
+
+08.03.2003
+A lot of interface fixes in profiles.
+Fixed bug with applying new password during profile edit.
+Added  ERROR_ON_SCREEN define to allow printing exact line/file of error to user browser.
+Serious code cleanup in main.cpp.
+
+09.03.2003
+Added announce update.
+
+12.03.2003
+Fixed compilation problem under Win32, some small interface fixes in profman, indexbuilder.
+
+14.03.2003
+Fixed important bugs in hashindex.cpp.
+
+16.03.2003
+Fixed HTML filtering in signature.
+Some changes in profile creation/modification in main.cpp.
+
+17.03.2003
+Fixed problem with profile creation with null password (core dump acquired sometimes).
+
+18.03.2003
+Fixed bug with url preparsing when tags was disabled.
+
+20.03.2003
+Fixed bug in hashindex.cpp (delete).
+Added last indexed message information to the search page.
+New version 2.0 pre beta1.
+
+23.03.2003
+Fixed some bugs with session management in logins.cpp, increased default session read buffer size.
+Added USER_SESSION_LIVE_TIME to basetypes.h.
+
+30.03.2003
+Changed design of conference (different thread dividers).
+Added main thread counter.
+
+04.04.2003
+Added own name colouring in message index.
+
+05.04.2003
+Some source code cleanup, more detailed comments (basetypes.h).
+
+26.04.2003
+Code cleanup, added decrementation of main thread counter during delete.
+Fixed new messages cookie refresh to "index only" refresh.
+
+27.04.2003
+Fixed workaround across announces (disabling it by cookie).
+
+28.04.2003
+Removed call to printing if topic mask is NULL.
+
+29.04.2003, alec (back from nowhere :))
+* replaced threads colors alternating from table to div && css
+  added DESIGN_open_dl_grey, css class "g", alternating grey color is DESIGN_THREADS_DIVIDER_grey
+* added cookie config option: if "+" acts as a link to the next new message
+* css classes names shortening: emplus->e
+ 
+05.05.2003, www
+Fixed bug with post time check if password is invalid.
+
+07.05.2003, www
+Added javascript to prevent duplicate post.
+Fixed some bugs in HTML.
+Fixed bug with maximum subject size in message.
+
+08.05.2003, www
+Added some parsing features (like ftp://) to boardtags.cpp.
+Returned email ackn checkbox to not logged in users.
+
+19.05.2003, alec, 20030519-autoparse-uinfo.diff
+* added https autoparsing, changed parsing code a bit
+* changes to CodeHttpString, uinfo link is now http-coded
+www: Added own function for time/data translation to human readable format.
+
+23.05.2003, alec, 20030523-whitespace-title.diff 
+* added FilterWhitespaces and filtering of ui->username when registering and
+  mes.MessageHeader when posting a new message
+  TODO: add filter to username if unregister posting
+* added filling database files with first 4 bytes in case if files are empty,
+  to avoid msg_id=0 in new boards
+* added printing of current topic to title (if any)
+ 
+28.05.2003, www
+Added greetings to login message.
+Added chexbox for disabling host name displaying in index.
+Added selected nick names coloring.
+
+29.05.2003, www
+Fixed some bugs with previous modification.
+Added private messages email ackn.
+Added checkbox to disable using private messages.
+
+31.05.2003, www
+Added preview for private messages and announces.
+Some code simplifying and modification in private messages printing.
+Added new feature "always send email ackn. for every post" to user profile.
+Fixed bug with invalid http encoding some urls.
+CodeHttpString() and FilterHTMLTags() in speller.cpp now can allocate storage from internal buffer, but default behaviour didn't change.
+Removed ICQ info in user profile if ICQ didn't specified.
+New version to 2.0 pre beta2.
+
+07.06.2003, www
+Added alternative displaying name (different from username) and right for use it.
+
+12.06.2003, www
+Fixed 2 vulnerabilities for Microsoft IE in tag parsing (allowed to use HTML).
+Changed color of empty message sign to BLACK.
+Changed encoding/title order in the HTML header, added encoding macro to messages.h.
+
+13.06.2003, www
+Changed the way of quick topic navigation, now cookies are used.
+
+14.06.2003, www
+Added checkbox for disabling alternative nick displaying.
+
+16.06.2003, www
+Some bugs with parsing names and html tags was fixed.
+
+20.06.2003, www
+Added disable signature checkbox to user settings.
+
+21.06.2003, www
+Session cookie is now attached to IP address.
+
+27.06.2003, www
+Added new sort mode to userlist (by right).
+Some design changes in post message form.
+
+01.07.2003, merge with hlt
+Fixed post problem under IIS (use CONTENT_LENGTH env. variable).
+Minor memory fixes.
+Fixed problem under Win32 with Fsize() bug check if file was already opened.
+www: Optionalize HTTP_REFERER check.
+
+02.07.2003, www
+Fixed bug with displaying several rolled threads coming one after another.
+Added signature printing to profman.
+
+30.09.2003, www
+Some interface fixes in search.
+Added checkbox about updating announce id to update announce form.
+Merge with demon:
+	* Allow admin post to closed threads
+	* Some source code fixes
+	* Favourites thread support
+
+01.10.2003, www
+Added checkbox to login form about session ip check.
+Enlarged session sequence to 8 bytes.
+
+07.10.2003, www
+Added activity log for last 10 min (hits/hosts).
+Added last posted message printing in collapsed threads.
+Changed version to 2.0 pre beta3.
+
+09.10.2003, www
+A lot of design changes (removed bottom link bar, etc.)
+Added checkbox to disable reply form in message view page.
+
+14.10.2003, www
+Little fix in profiles.cpp (sort user fix) - USERRIGHT_SUPERUSER will only be placed to right if other right exists in all profiles list. Allows viewing all moderators in one group.
+Some code cleanup, added define for disabling activity log support.
+
+11.05.2004, www
+New distributive creation was started.
+Profman and reindex was merged to wcmanager tool.
+
+18.07.2004, www
+Added change message feature.
+
+18.08.2004, demon
+Fixed bug with default settings while opening configure=action
+Added saving view configuration to profile
+Added simple banned list editor
+Added mail subject  encoding (base64), going to rfc in mail
+Added new board tags ( SUP, SUB and STRIKE)
+Removed p.gif between threads, added border style for threads div's
+Style changes ( body, table, padding, margin and others)
+Changed version to 2.0 pre beta4.
+
+22.08.2004, www
+Some code simplifications for main.cpp.
+
+?, www
+Timezone support added.
+
+25.10.2004, demon
+Timezone setting added to profile.
+Removing SCookies[] massive, cookies parsing reforming.
+Changing new session behavior - all messages are in read state. 
+
+27.10.2004, demon
+Fixed security check (flag to allow creating new message and thread)
+Design bug - unclosed tag.
+
+21.01.2005, hlt (demon - it's rolled back due to bug?!)
+Fixed persmsg to users with html chars in their names - now names are stored in db as raw, not escaped html
+Fixed issue with ?persmsgform not filtering html tags (html javascript script injection exploit)
blob - /dev/null
blob + a9d7f05cf1373a972625cf289d82bb91fc219259 (mode 644)
--- /dev/null
+++ src/Makefile
@@ -0,0 +1,71 @@
+#
+# Makefile for wwwconf, version by alec@3ka.mipt.ru
+# Created 24.01.2003
+#
+
+CC=g++
+# -pg -g
+CXX=$(CC)
+
+FILES_INDEX= sha1.cpp statfs.cpp dbase.cpp main.cpp announces.cpp boardtags.cpp speller.cpp security.cpp freedb.cpp indexer.cpp profiles.cpp logins.cpp hashindex.cpp searcher.cpp error.cpp sendmail.cpp colornick.cpp activitylog.cpp
+FILES_DBTOOL= freedb.cpp profiles.cpp hashindex.cpp profman.cpp indexer.cpp searcher.cpp
+SOURCES=$(FILES_INDEX) $(FILES_DBTOOL)
+
+OBJECTS_INDEX= $(FILES_INDEX:.cpp=.o)
+OBJECTS_DBTOOL= $(FILES_DBTOOL:.cpp=.o)
+
+prefix=/home/estet/wwwconf10 
+inst = /usr/bin/install -c
+
+CFLAGS:= -O2 -fno-exceptions
+
+
+#.if (.depend,$(wildcard .depend))
+#include .depend
+#.else
+#@echo "You do not have dep file, run make dep"
+#.endif
+
+all: index dbtool
+	@echo Compiling Done
+
+index: $(OBJECTS_INDEX)
+	$(CC) $(CFLAGS) -o index.cgi $(OBJECTS_INDEX)
+dbtool: $(OBJECTS_DBTOOL)
+	$(CC) $(CFLAGS) -o dbtool $(OBJECTS_DBTOOL)
+
+#
+# include dependency files if they exist
+#
+#ifneq ($(wildcard .depend),)
+#include .depend
+#endif
+
+#creating dependencies
+dep:
+	@echo "Creating .depend"
+	@rm -f .depend
+	$(CC) -MM -MG $(SOURCES) >> .depend
+
+
+clean:
+	@rm -f *.o
+	@rm -f index.cgi dbtool 
+	@echo Clean complete
+
+install: all
+	@echo Installing binaries and tools to ${prefix}
+	cp ${prefix}/dbtool ${prefix}/dbtool_prev
+	cp ${prefix}/index.cgi ${prefix}/index.cgi_prev
+	${inst} -m 751 index.cgi ${prefix}/index.cgi
+	${inst} -m 750 dbtool ${prefix}
+
+uninstall: ${prefix}/index.cgi_prev ${prefix}/dbtool_prev 
+	@echo UnInstalling backed up binaries and tools 
+	cp ${prefix}/index.cgi_prev ${prefix}/index.cgi
+	cp ${prefix}/dbtool_prev ${prefix}/dbtool
+
+fake: index 
+	@echo Installing binaries and tools to ${prefix}
+	${inst} -m 751 index.cgi ${prefix}/index-dev.cgi
+	${inst} -m 750 dbtool ${prefix}/dbtool-dev
blob - /dev/null
blob + 48853d6df89f37f04996ab170b75b772c0d4e350 (mode 644)
--- /dev/null
+++ src/activitylog.cpp
@@ -0,0 +1,247 @@
+/***************************************************************************
+                          activitylog.cpp  -  board activity logger
+                             -------------------
+    begin                : Mon Oct 6 2003
+    copyright            : (C) 2003 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "activitylog.h"
+
+#define ACTIVITY_CONTROL_TIME	10*60	// 10min
+#define BLOCKREADCOUNT	1000
+
+void inline swap(DWORD *a, DWORD *b)
+{
+	register DWORD t=*a;
+	*a=*b;
+	*b = t;
+}
+
+int RegisterActivityFrom(DWORD IP, DWORD &hostcnt, DWORD &hitcnt)
+{
+	WCFILE *f = NULL, *f1 = NULL;
+	DWORD tm, tm1, fin, fin1;
+	int disfileok = 0, addfileok = 0, finalizedone = 0, swapdone = 0;
+	hostcnt = hitcnt = 0;
+	DWORD crtime = time(NULL);
+
+	if((f = wcfopen(F_ACTIVITYLOG1, FILE_ACCESS_MODES_RW)) == NULL) {
+		// create file
+		if((f = wcfopen(F_ACTIVITYLOG1, FILE_ACCESS_MODES_CW)) != NULL)
+		{
+			DWORD x[2];
+			memset(x,0,8);
+			fCheckedWrite(&x, 8, f);
+			wcfclose(f);
+			f = wcfopen(F_ACTIVITYLOG1, FILE_ACCESS_MODES_RW);
+			if(f) lock_file(f);
+		}
+		else goto failed;
+	}
+	else lock_file(f);
+	if((f1 = wcfopen(F_ACTIVITYLOG2, FILE_ACCESS_MODES_RW)) == NULL) {
+		// create file
+		if((f1 = wcfopen(F_ACTIVITYLOG2, FILE_ACCESS_MODES_CW)) != NULL)
+		{
+			DWORD x[2];
+			memset(x,0,8);
+			fCheckedWrite(&x, 8, f1);
+			wcfclose(f1);
+			f1 = wcfopen(F_ACTIVITYLOG2, FILE_ACCESS_MODES_RW);
+			if(f1) lock_file(f1);
+		}
+		else goto failed;
+	}
+	else lock_file(f1);
+
+	if(!fCheckedRead(&tm, 4, f))
+		goto failed;
+	if(!fCheckedRead(&tm1, 4, f1))
+		goto failed;
+	if(!fCheckedRead(&fin, 4, f))
+		goto failed;
+	if(!fCheckedRead(&fin1, 4, f1))
+		goto failed;
+
+	// find file for displaying (it will be f1)
+	if(crtime - 2*ACTIVITY_CONTROL_TIME <= tm  && tm < crtime - ACTIVITY_CONTROL_TIME )
+	{
+		swap((DWORD*)(&f), (DWORD*)(&f1));
+		swap(&tm, &tm1);
+		swap(&fin, &fin1);
+
+		// to know path to the file
+		swapdone = !swapdone;
+
+		disfileok = 1;
+	}
+	if(crtime - 2*ACTIVITY_CONTROL_TIME <= tm1 && tm1 < crtime - ACTIVITY_CONTROL_TIME )
+	{
+		disfileok = 1;
+	}
+
+	// find file for saving (will be f)
+	if(crtime - ACTIVITY_CONTROL_TIME <= tm && tm < crtime)
+	{
+		addfileok = 1;
+	}
+	if(crtime - ACTIVITY_CONTROL_TIME <= tm1 && tm1 < crtime)
+	{
+		swap((DWORD*)(&f), (DWORD*)(&f1));
+		swap(&tm, &tm1);
+		swap(&fin, &fin1);
+
+		// to know path to the file
+		swapdone = !swapdone;
+
+		addfileok = 1;
+	}
+
+	// parse file with display information
+	if(disfileok) {
+		if(!fin1) {
+			DWORD rr, cn, i;
+			SActivityLogRecord* buf;
+
+			// finalize file
+			buf = (SActivityLogRecord*)malloc(sizeof(SActivityLogRecord)*BLOCKREADCOUNT);
+			while(!wcfeof(f1)) {
+				rr = wcfread(buf, 1, sizeof(SActivityLogRecord)*BLOCKREADCOUNT, f1);
+
+				if((rr%sizeof(SActivityLogRecord)) != 0) {
+					/* read error */
+					break;
+				}
+				cn = rr/sizeof(SActivityLogRecord);
+				hostcnt += cn;
+				for(i = 0; i < cn; i++) {
+					hitcnt += buf[i].Count;
+				}
+			}
+			free(buf);
+			wcfflush(f1);
+			// truncate end of file
+#ifdef WIN32	
+			wctruncate(f1, 4);
+#else
+			truncate(swapdone ? F_ACTIVITYLOG1 : F_ACTIVITYLOG2, 4);
+#endif
+			wcfseek(f1, 0, SEEK_END);
+			rr = 1;
+			fCheckedWrite(&rr, 4, f1);
+			fCheckedWrite(&hitcnt, 4, f1);
+			fCheckedWrite(&hostcnt, 4, f1);
+			finalizedone = 1;
+		}
+		else {
+			// just read info from file
+			fCheckedRead(&hitcnt, 4, f1);
+			fCheckedRead(&hostcnt, 4, f1);
+		}
+		// release file lock as soon as possible (won't wait for the end of this fuction)
+		wcfflush(f1);
+		unlock_file(f1);
+		wcfclose(f1);
+		f1 = NULL;
+	}
+
+	if(addfileok) {
+		DWORD rr, cn, pos, done = 0, i;
+		SActivityLogRecord* buf;
+
+		// add ip to file
+		buf = (SActivityLogRecord*)malloc(sizeof(SActivityLogRecord)*BLOCKREADCOUNT);
+		while(!wcfeof(f)) {
+			pos = wcftell(f);
+			rr = wcfread(buf, 1, sizeof(SActivityLogRecord)*BLOCKREADCOUNT, f);
+
+			if((rr%sizeof(SActivityLogRecord)) != 0) {
+				/* read error */
+				done = 1;
+				break;
+			}
+			cn = rr/sizeof(SActivityLogRecord);
+			for(i = 0; i < cn; i++) {
+				if(buf[i].IP == IP) {
+					buf[i].Count++;
+					buf[i].Time = time(NULL);
+					done = 1;
+					wcfseek(f, pos, SEEK_SET);
+					fCheckedWrite(buf, sizeof(SActivityLogRecord)*(i+1), f);
+					break;
+				}
+			}
+			if(done) break;
+		}
+		free(buf);
+		if(!done) {
+			SActivityLogRecord ss;
+			ss.Count = 1;
+			ss.IP = IP;
+			ss.Time = crtime;
+			wcfseek(f, 0, SEEK_END);
+			fCheckedWrite(&ss, sizeof(SActivityLogRecord), f);
+		}
+	}
+	else {
+		DWORD rr;
+		SActivityLogRecord ss;
+
+		// if it's filalized file, let's add activity to the history
+		if(fin) {
+			WCFILE *f2;
+			DWORD buf[3];
+			// add to achive 
+			fCheckedRead(&hitcnt, 4, f);
+			fCheckedRead(&hostcnt, 4, f);
+
+			if((f2 = wcfopen(F_ACTIVITYARCH, FILE_ACCESS_MODES_RW)) == NULL) {
+				// create file
+				f2 = wcfopen(F_ACTIVITYARCH, FILE_ACCESS_MODES_CW);
+			}
+
+			if(f2 != NULL) {
+				lock_file(f2);
+				wcfseek(f2, 0, SEEK_END);
+				buf[0] = tm; buf[1] = hitcnt; buf[2] = hostcnt;
+				fCheckedWrite(&buf, 12, f2);
+				wcfflush(f2);
+				unlock_file(f2);
+				wcfclose(f2);
+			}
+		}
+
+		ss.Count = 1;
+		ss.IP = IP;
+		ss.Time = crtime;
+
+		wcfflush(f);
+#ifdef WIN32	
+		wctruncate(f, 8);
+#else
+		truncate(swapdone ? F_ACTIVITYLOG2 : F_ACTIVITYLOG1, 4);
+#endif
+		wcfseek(f, 4, SEEK_SET);
+		rr = 0;
+		fCheckedWrite(&rr, 4, f);
+		fCheckedWrite(&ss, sizeof(SActivityLogRecord), f);
+		// make header
+		wcfseek(f, 0, SEEK_SET);
+		if(!finalizedone) rr = crtime;
+		else rr = tm1 + ACTIVITY_CONTROL_TIME;
+		fCheckedWrite(&rr, 4, f);
+	}
+failed:
+	if(f) {
+		wcfflush(f);
+		unlock_file(f);
+		wcfclose(f);
+	}
+	if(f1) {
+		wcfflush(f1);
+		unlock_file(f1);
+		wcfclose(f1);
+	}
+	return 0;
+}
blob - /dev/null
blob + e48669e376b52b1e908fcc19b4112d1f0a370425 (mode 644)
--- /dev/null
+++ src/activitylog.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+                          activitylog.h  -  board activity logger header
+                             -------------------
+    begin                : Mon Oct 6 2003
+    copyright            : (C) 2003 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef ACTYVITYLOG_H_INCLUDED
+#define ACTYVITYLOG_H_INCLUDED
+
+#include "basetypes.h"
+
+struct SActivityLogRecord
+{
+	DWORD IP;
+	DWORD Count;
+	DWORD Time;
+};
+
+int RegisterActivityFrom(DWORD IP, DWORD &hostcnt, DWORD &hitcnt);
+
+#endif
blob - /dev/null
blob + 861a225fb0afbe4b99565df6eb1e979fb951f040 (mode 644)
--- /dev/null
+++ src/announces.cpp
@@ -0,0 +1,323 @@
+/***************************************************************************
+                          announces.cpp  -  board announces support
+                             -------------------
+    begin                : Mon Feb 24 2003
+    copyright            : (C) 2001 - 2003 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "announces.h"
+#include "error.h"
+
+static void* CreateAnnounceFile()
+{
+	FILE *f;
+	f = fopen(F_GLOBAL_ANN, FILE_ACCESS_MODES_CW);
+	if(f) {
+		// announces number starting from 1
+		DWORD x = 1;
+		// write starting unique id
+		if(fwrite(&x, 1, sizeof(x), f) != sizeof(x)) {
+			fclose(f);
+			f = NULL;
+		}
+		else {
+			fclose(f);
+			f = fopen(F_GLOBAL_ANN, FILE_ACCESS_MODES_RW);
+		}
+	}
+	return f;
+}
+
+static void* CreateAnnounceWCFile()
+{
+	WCFILE *f;
+	f = wcfopen(F_GLOBAL_ANN, FILE_ACCESS_MODES_CW);
+	if(f) {
+		// announces number starting from 1
+		DWORD x = 1;
+		// write starting unique id
+		if(wcfwrite(&x, 1, sizeof(x), f) != sizeof(x)) {
+			wcfclose(f);
+			f = NULL;
+		}
+		else {
+			wcfclose(f);
+			f = wcfopen(F_GLOBAL_ANN, FILE_ACCESS_MODES_RW);
+		}
+	}
+	return f;
+}
+
+int ReadLastAnnounceNumber(DWORD *an)
+{
+	FILE *f;
+	int ret = 0;
+
+	f = fopen(F_GLOBAL_ANN, FILE_ACCESS_MODES_RW);
+	if(!f) return 0;
+	if(fread(an, 1, sizeof(DWORD), f) == sizeof(DWORD))
+		ret = 1;
+	fclose(f);
+	return ret;
+}
+
+int PostGlobalAnnounce(char *username, DWORD uniqid, char *announce, DWORD ttl, DWORD flags)
+{
+	WCFILE *f;
+	DWORD siz;
+	SGlobalAnnounce an;
+	DWORD id;
+
+	if((f = wcfopen(F_GLOBAL_ANN, FILE_ACCESS_MODES_RW)) == NULL) {
+		if((f = (WCFILE*)CreateAnnounceWCFile()) == NULL) {
+			return ANNOUNCES_RETURN_IO_ERROR;
+		}
+	}
+	// prepare announce structure
+	strcpy(an.Announce, announce);
+	strcpy(an.From, username);
+	an.UIdFrom = uniqid;
+	an.TTL = ttl;
+	an.Date = time(NULL);
+	an.Flags = flags;
+	memset(an.Reserved, 0, sizeof(an.Reserved));
+	// write announce
+	lock_file(f);
+	if(!fCheckedRead(&id, sizeof(id), f)) {
+		unlock_file(f);
+		wcfclose(f);
+		return ANNOUNCES_RETURN_DB_ERROR;
+	}
+	// save number
+	an.Number = id;
+	// increment number
+	id++;
+	if(wcfseek(f, 0, SEEK_SET) != 0) {
+		unlock_file(f);
+		wcfclose(f);
+		return ANNOUNCES_RETURN_IO_ERROR;
+	}
+	if(!fCheckedWrite(&id, sizeof(id), f)) {
+		unlock_file(f);
+		wcfclose(f);
+		return ANNOUNCES_RETURN_IO_ERROR;
+	}
+	if(wcfseek(f, 0, SEEK_END) != 0) {
+		unlock_file(f);
+		wcfclose(f);
+		return ANNOUNCES_RETURN_IO_ERROR;
+	}
+	// start transcation
+	siz = wcftell(f);
+	if(!fCheckedWrite(&an, sizeof(SGlobalAnnounce), f)) {
+		// rolling back
+#ifdef WIN32	
+		wctruncate(f, siz);
+#else
+		truncate(F_GLOBAL_ANN, siz);
+#endif
+		id--;
+		if(wcfseek(f, 0, SEEK_END) == 0) {
+			fCheckedWrite(&id, sizeof(id), f);
+		}
+		unlock_file(f);
+		wcfclose(f);
+		return ANNOUNCES_RETURN_IO_ERROR;
+	}
+	unlock_file(f);
+	wcfclose(f);
+	return ANNOUNCES_RETURN_OK;
+}
+
+int ReadGlobalAnnounces(time_t ct, SGlobalAnnounce **ga, DWORD *cnt)
+{
+	FILE *f;
+	DWORD i = 0, rd;
+	SGlobalAnnounce *an;
+
+	*ga = NULL;
+	*cnt = 0;
+
+	an = (SGlobalAnnounce*)malloc(sizeof(SGlobalAnnounce));
+	if(!an) return ANNOUNCES_RETURN_LOW_RES;
+
+	if((f = fopen(F_GLOBAL_ANN, FILE_ACCESS_MODES_R)) == NULL) {
+		if((f = (FILE*)CreateAnnounceFile()) == NULL) {
+			free(an);
+			return ANNOUNCES_RETURN_IO_ERROR;
+		}
+	}
+	if(fseek(f, sizeof(DWORD), SEEK_SET) != 0) {
+		free(an);
+		return ANNOUNCES_RETURN_IO_ERROR;
+	}
+	while(!feof(f))
+	{
+		if((rd = fread(&(an[i]), 1, sizeof(SGlobalAnnounce), f)) != sizeof(SGlobalAnnounce)) {
+			if(rd != 0) {
+				free(an);
+				fclose(f);
+				return ANNOUNCES_RETURN_DB_ERROR;
+			}
+			else break;
+		}
+		i++;
+		an = (SGlobalAnnounce*)realloc(an, (i+1)*sizeof(SGlobalAnnounce));
+	}
+	fclose(f);
+	*cnt = i;
+	*ga = an;
+	return ANNOUNCES_RETURN_OK;
+}
+
+int DeleteGlobalAnnounce(DWORD id, DWORD uniqid)
+{
+	WCFILE *f;
+	DWORD pos, fsize, rd;
+	SGlobalAnnounce *an;
+
+	an = (SGlobalAnnounce*)malloc(sizeof(SGlobalAnnounce));
+	if(!an) return ANNOUNCES_RETURN_LOW_RES;
+
+	if((f = wcfopen(F_GLOBAL_ANN, FILE_ACCESS_MODES_RW)) == NULL) {
+		free(an);
+		return ANNOUNCES_RETURN_IO_ERROR;
+	}
+	lock_file(f);
+	if(wcfseek(f, sizeof(DWORD), SEEK_SET) != 0) {
+		free(an);
+		return ANNOUNCES_RETURN_IO_ERROR;
+	}
+	an->Number = 0xffffffff;
+	while(!wcfeof(f))
+	{
+		pos = wcftell(f);
+		if((rd = wcfread(an, 1, sizeof(SGlobalAnnounce), f)) != sizeof(SGlobalAnnounce)) {
+			if(rd != 0) {
+				free(an);
+				wcfclose(f);
+				return ANNOUNCES_RETURN_DB_ERROR;
+			}
+			else break;
+		}
+		if(an->Number == id && (uniqid == 0 || an->UIdFrom == uniqid)) break;
+	}
+	if(an->Number == id) {
+		// let's delete it
+		int i = 0;
+		while(!wcfeof(f))
+		{
+			if((rd = wcfread(&(an[i]), 1, sizeof(SGlobalAnnounce), f)) != sizeof(SGlobalAnnounce)) {
+				if(rd != 0) {
+					free(an);
+					wcfclose(f);
+					return ANNOUNCES_RETURN_DB_ERROR;
+				}
+				else break;
+			}
+			i++;
+			an = (SGlobalAnnounce*)realloc(an, (i+1)*sizeof(SGlobalAnnounce));
+		}
+		fsize = wcftell(f);
+		fsize -= sizeof(SGlobalAnnounce);
+		if(wcfseek(f, pos, SEEK_SET) != 0) {
+			free(an);
+			wcfclose(f);
+			return ANNOUNCES_RETURN_DB_ERROR;
+		}
+		if(wcfwrite(an, 1, sizeof(SGlobalAnnounce)*i, f) != sizeof(SGlobalAnnounce)*i) {
+			free(an);
+			wcfclose(f);
+			return ANNOUNCES_RETURN_DB_ERROR;
+		}
+		free(an);
+		// !!!!!!!!!!!!
+		wcfflush(f);
+		// truncate end of file
+#ifdef WIN32	
+		wctruncate(f, fsize);
+#else
+		truncate(F_GLOBAL_ANN, fsize);
+#endif
+		unlock_file(f);
+		wcfclose(f);
+	}
+	else {
+		// announce not found
+		unlock_file(f);
+		wcfclose(f);
+		return ANNOUNCES_RETURN_NOT_FOUND;
+	}
+
+	return ANNOUNCES_RETURN_OK;
+}
+
+int UpdateGlobalAnnounce(DWORD id, char *username, DWORD uniqid, char *announce,
+		DWORD ttl, DWORD flags, DWORD updateopt)
+{
+	WCFILE *f;
+	DWORD pos, rd;
+	SGlobalAnnounce *an;
+
+	an = (SGlobalAnnounce*)malloc(sizeof(SGlobalAnnounce));
+	if(!an) return ANNOUNCES_RETURN_LOW_RES;
+
+	if((f = wcfopen(F_GLOBAL_ANN, FILE_ACCESS_MODES_RW)) == NULL) {
+		free(an);
+		return ANNOUNCES_RETURN_IO_ERROR;
+	}
+	lock_file(f);
+	if(wcfseek(f, sizeof(DWORD), SEEK_SET) != 0) {
+		free(an);
+		return ANNOUNCES_RETURN_IO_ERROR;
+	}
+	an->Number = 0xffffffff;
+	while(!wcfeof(f))
+	{
+		pos = wcftell(f);
+		if((rd = wcfread(an, 1, sizeof(SGlobalAnnounce), f)) != sizeof(SGlobalAnnounce)) {
+			if(rd != 0) {
+				free(an);
+				wcfclose(f);
+				return ANNOUNCES_RETURN_DB_ERROR;
+			}
+			else break;
+		}
+		if(an->Number == id) break;
+	}
+	if(an->Number == id) {
+		// let's update it
+		strcpy(an->Announce, announce);
+		if((updateopt & ANNOUNCES_UPDATE_OPT_USER)) {
+			strcpy(an->From, username);
+			an->UIdFrom = uniqid;
+		}
+		if((updateopt & ANNOUNCES_UPDATE_OPT_TTL)) an->TTL = ttl;
+		if((updateopt & ANNOUNCES_UPDATE_OPT_TIME)) an->Date = time(NULL);
+		if((updateopt & ANNOUNCES_UPDATE_OPT_FLAGS)) an->Flags = flags;
+		memset(an->Reserved, 0, sizeof(an->Reserved));
+		if(wcfseek(f, pos, SEEK_SET) != 0) {
+			free(an);
+			wcfclose(f);
+			return ANNOUNCES_RETURN_DB_ERROR;
+		}
+		if(wcfwrite(an, 1, sizeof(SGlobalAnnounce), f) != sizeof(SGlobalAnnounce)) {
+			free(an);
+			wcfclose(f);
+			return ANNOUNCES_RETURN_DB_ERROR;
+		}
+		free(an);
+		unlock_file(f);
+		wcfclose(f);
+	}
+	else {
+		// announce not found
+		unlock_file(f);
+		wcfclose(f);
+		return ANNOUNCES_RETURN_NOT_FOUND;
+	}
+
+	return ANNOUNCES_RETURN_OK;
+
+}
blob - /dev/null
blob + 81ecc93e81e05ec8ed4365861a86ead3b7717e1a (mode 644)
--- /dev/null
+++ src/announces.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+                          announces.h  -  board announces support header
+                             -------------------
+    begin                : Mon Feb 24 2003
+    copyright            : (C) 2001 - 2003 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef ANNOUNCES_H_INCLUDED
+#define ANNOUNCES_H_INCLUDED
+
+#include "basetypes.h"
+#include "profiles.h"
+
+#define GLOBAL_ANNOUNCE_MAXSIZE 513
+
+#define ANNOUNCES_RETURN_OK			0
+#define ANNOUNCES_RETURN_IO_ERROR	1
+#define ANNOUNCES_RETURN_DB_ERROR	2
+#define ANNOUNCES_RETURN_LOW_RES	3
+#define ANNOUNCES_RETURN_NOT_FOUND	4
+
+#define ANNOUNCES_UPDATE_OPT_USER	0x01
+#define ANNOUNCES_UPDATE_OPT_TIME	0x02
+#define ANNOUNCES_UPDATE_OPT_FLAGS	0x04
+#define ANNOUNCES_UPDATE_OPT_TTL	0x08
+
+#pragma pack(1)
+struct SGlobalAnnounce {
+	char Announce[GLOBAL_ANNOUNCE_MAXSIZE];
+
+	char From[PROFILES_MAX_USERNAME_LENGTH];
+	DWORD UIdFrom;	// UniqID of poster
+
+	time_t Date;	// post date
+	DWORD TTL;		// Time To Live of this announce
+
+	DWORD Flags;	// flags of the post
+
+	DWORD Number;	// unique announce number (for identification)
+
+	DWORD Reserved[2];	// reserved for the future use
+};
+#pragma pack(4)
+
+/* Post announce as selected user.
+ * It don't check security permitions of poster !
+ */
+int PostGlobalAnnounce(char *username, DWORD uniqid, char *announce, DWORD ttl, DWORD flags);
+
+/* Read annonces that implies to 'ct' date. (!!! ignored for now !!!)
+ */
+int ReadGlobalAnnounces(time_t ct, SGlobalAnnounce **ga, DWORD *cnt);
+
+/* Delete global announce by id
+ */
+int DeleteGlobalAnnounce(DWORD id, DWORD uniqid);
+
+/* Read last used announce number
+ */
+int ReadLastAnnounceNumber(DWORD *an);
+
+/* Update announce (using updateopt flags) by id
+ */
+int UpdateGlobalAnnounce(DWORD id, char *username, DWORD uniqid, char *announce,
+		DWORD ttl, DWORD flags, DWORD updateopt);
+
+#endif // of ANNOUNCES_H_INCLUDED
blob - /dev/null
blob + 7be775ecde49bc54c007ad713bc64745b14ffe86 (mode 644)
--- /dev/null
+++ src/basetypes.h
@@ -0,0 +1,547 @@
+/***************************************************************************
+                          basetypes.h  -  base types and definitions
+                             -------------------
+    begin                : Wed Mar 14 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef BASETYPES_H_INCLUDED
+#define BASETYPES_H_INCLUDED
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <locale.h>
+#include <errno.h>
+#include <ctype.h>
+
+/****************** Log&Debug ******************/
+// can be 0 or 1 
+// 0 - disabled [Recomended]
+// 1 - enabled
+#define _DEBUG_ 1
+//
+// can be 0, 1, 2
+// 0 - fully disable, even critical errors
+// 1 - disable, but critical error [Recommended]
+// 2 - fully enable (information, critical errors, etc.)
+#define ENABLE_LOG  2
+//
+// should file and string of each global error be showed to the user (useful for debug)
+#define ERROR_ON_SCREEN 1
+/***********************************************/
+
+/*************************** language and locale ***************************/
+#ifdef WIN32
+#define LANGUAGE_LOCALE "Russian"     // Windows
+#else
+#define LANGUAGE_LOCALE "ru_RU.CP1251"    // Unix
+#endif
+
+// should we set up locale during initialization
+#define USE_LOCALE 0
+
+#define RT_REDIRECT 1
+
+// spelling check before post message
+#define SPELLING_CHECK 1
+
+// banned ip check before post message
+#define BANNED_CHECK 1
+
+// if message body not have be empty
+#define MSG_REQURED_BODY 0
+
+// enable IP to DNS name reslove Host Addresses
+#define IP_TO_HOSTNAME_RESOLVE 1
+
+/* date&time output style
+  Possible values:
+   1 - standart ctime output
+   2 - MM/DD/YY
+   3 - DD/MM/YY             */
+#define DATETIME_STYLE 3
+
+#define DATETIME_DEFAULT_TIMEZONE 3
+
+// show or not host names in messages
+#define SHOW_HOST_NAME 1
+
+// allow remark new messages
+// 1 = mark with +
+// 2 = mark will be linked to the next new message
+#define ALLOW_MARK_NEW_MESSAGES 2
+
+// should wwwconf change header of page on different pages
+#define STABLE_TITLE 0
+
+// antispam function control
+#define ALLOW_ANTISPAM 1
+// post time limit (in seconds), reason to decide that it's flood
+// *** processed ONLY if antispam function active ***
+#define POST_TIME_LIMIT 10
+
+// refresh to posted message time
+#define AUTO_REFRESH_TIME 3
+
+/*****************************************************************************/
+// topic support
+#define TOPICS_SYSTEM_SUPPORT 1
+
+// should we allow posting messages as unregistred when the same registred user exists
+#define POST_ALLOW_UNDER_SAME_NICK 0
+
+//**************************************
+// support for user profiles
+// *** if this feature is turned off NOBODY security byte and rigth will be applied to all users ***
+#define USER_PROFILES_SUPPORT 1
+
+#define USER_ALT_NICK_SPELLING_SUPPORT 1
+
+// default session live time (for logged in user)
+#define USER_SESSION_LIVE_TIME  360000
+
+// user personal message support, allows to use conference as private messenger
+#define USER_PERSONAL_MESSAGE_SUPPORT 1
+//**************************************
+
+// user favourites support, allow save messages in profile
+// 1 = allow save any message to favourites
+// 2 = allow save only parent message in thread
+#define USER_FAVOURITES_SUPPORT 2
+
+// support for global announces
+#define GLOBAL_ANNOUNCES_SUPPORT  1
+
+// support for user activity internal counters
+#define ACTIVITY_LOGGING_SUPPORT  1
+
+//  top and bottom banner located in file or defined statically
+#define USE_TEXT_BOTTOMBANNER 1
+#define USE_TEXT_TOPBANNER    1
+
+//delete unused accounts 
+#define CLEANUP_IDLE_USERS 1
+
+//  count of messages on one page of search
+#define SEARCH_MES_PER_PAGE_COUNT 100
+
+/********************* DEFAULT USER AND MESSAGE PARAMETERS *******************/
+
+/******** message database structures length *********/
+#define MESSAGE_HEADER_LENGTH 100
+#define AUTHOR_NAME_LENGTH    30
+#define HOST_NAME_LENGTH    60
+
+/************* default not logged users parameters ***************/
+#define DEFAULT_NOBODY_SECURITY_BYTE  10
+#define DEFAULT_NOBODY_HDR_SEC_BYTE   255
+#define DEFAULT_NOBODY_RIGHT    USERRIGHT_CREATE_MESSAGE | USERRIGHT_VIEW_MESSAGE | USERRIGHT_CREATE_MESSAGE_THREAD | USERRIGTH_PROFILE_CREATE
+
+/******** default user creation parameters (logged users) ********/
+#define DEFAULT_USER_SECURITY_BYTE    2
+#define DEFAULT_USER_HDR_SEC_BYTE   11
+#define DEFAULT_USER_RIGHT        USERRIGHT_CREATE_MESSAGE | USERRIGHT_VIEW_MESSAGE | USERRIGHT_CREATE_MESSAGE_THREAD | USERRIGTH_PROFILE_MODIFY | USERRIGTH_PROFILE_CREATE
+#define USER_DEFAULT_PROFILE_CREATION_FLAGS PROFILES_FLAG_VISIBLE_EMAIL | PROFILES_FLAG_VIEW_SETTINGS
+
+/******** default admin creation parameters (moderators) *********/
+#define DEFAULT_ADMIN_SECURITY_BYTE   0
+#define DEFAULT_ADMIN_HDR_SEC_BYTE    0
+#define DEFAULT_ADMIN_RIGHT     USERRIGHT_SUPERUSER
+
+/******************** default "own settings" *********************/
+// which will be used too if browser does not support cookie
+#define CONFIGURE_SETTING_DEFAULT_lsel      2     // 1 - by time
+#define CONFIGURE_SETTING_DEFAULT_tv      8     // 12 hours
+#define CONFIGURE_SETTING_DEFAULT_tt      1     // hours
+#define CONFIGURE_SETTING_DEFAULT_tc      100
+#define CONFIGURE_SETTING_DEFAULT_ss      SHOW_MESSAGE_STYLE_HRON_FORWARD
+#define CONFIGURE_SETTING_DEFAULT_dsm     0
+#define CONFIGURE_SETTING_DEFAULT_topics    0xFFFFFFFF
+#define CONFIGURE_SETTING_DEFAULT_toverride   0     // own settings
+
+/********************** common params **********************/
+#define MY_CGI_URL  ""
+#define MY_HOST_URL ""
+
+#define BOARD_PIC_URL "pic/"            // smile dir (HTTP path to pic with smiles)
+                          //
+                          // NOTE: it's not absolute path on server
+                          // it's only HTTP path
+
+#define HTTP_REFERER_CHECK  0 
+// this string should be in HTTP_REFERER to pass trough the test
+#define ALLOWED_HTTP_REFERER "rt.mipt.ru"
+
+// MAIL
+
+// WC_TYPE 
+// 1 - via smtp  ( localhost or remote server)
+// 2 - via command line (sendmail in unix like system)
+
+#define MA_TYPE     1
+
+#define MA_READURL    "http://192.168.1.7/"
+#define MA_FROM     "automailer-noreply@rt.mipt.ru"
+// there should be smtp server ip or path to sendmail-like program
+#define MA_SENDER     "localhost"
+#define ADMIN_MAIL  "sergeyb@parallels.ru"
+
+#define COOKIE_NAME_STRING      "RTBB="
+#define COOKIE_SESSION_NAME     "SessionRT="
+#define COOKIE_EXPIRATION_DATE    "Fri, 31-Dec-2009 00:00:00 GMT;"
+#define COOKIE_SERVER_PATH      "/;"
+
+// the maximum size for top and bottom files
+#define MAX_HTML_FILE_SIZE 65535
+
+/******************* perfomace parameters *******************/
+
+// optimize index building for short index (about 300-500 messages in index)
+// it will sligtly improove perfomance on HDD with high seek time
+#define SHORT_INDEX_OPTIMIZATION  1
+
+// count of message table entries for caching working with it
+// this value is limited to 32000
+#define READ_MESSAGE_TABLE  2000
+
+// count of message index entries to cache working with it
+// this value limited to 32000
+#define READ_MESSAGE_HEADER 2*65535/sizeof(SMessage)
+
+
+///////////////////////////////////////////////////////////////////////////////
+////////////////////  Platform dependent parameters
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef WIN32
+/*********WIN32*********/
+#include <windows.h>
+#include <io.h>
+#include <direct.h>
+#include <winsock.h>
+
+#pragma comment(lib, "ws2_32.lib")
+
+typedef struct _WCFILE {
+  HANDLE  MutexHandle;  // mutex for file locking
+  FILE *f;        // file hanlde
+} WCFILE;
+
+inline WCFILE* wcfopen(char *fname, char *mode)
+{
+  WCFILE *f = (WCFILE*)malloc(sizeof(WCFILE));
+  char *mn = (char*)malloc(strlen(fname) + 20);
+  if(!f || !mn)
+    goto FAILED;
+  
+  f->f = fopen(fname, mode);
+  if(f->f == NULL)
+    goto FAILED;
+  
+  strcpy(mn, "Global\\"); // we use global namespace
+  strcat(mn, fname);
+  f->MutexHandle = ::CreateMutex(NULL, FALSE, mn);
+  if(!f->MutexHandle) {
+    fclose(f->f);
+    goto FAILED;
+  }
+  free(mn);
+  return f;
+  
+FAILED:
+  if(f) free(f);
+  if(mn) free(mn);
+  return NULL;
+}
+
+inline void wcfclose(WCFILE *f)
+{
+  fclose(f->f);
+  ::ReleaseMutex(f->MutexHandle);
+  ::CloseHandle(f->MutexHandle);
+  free(f);
+}
+
+inline void flock(WCFILE *a, int b)
+{
+  if(b == 1) {
+    ::WaitForSingleObject(a->MutexHandle, INFINITE);
+  }
+  else {
+    ::ReleaseMutex(a->MutexHandle);
+  }
+}
+
+#define wcfseek(a,b,c) fseek(a->f,b,c)
+#define wcfeof(a) feof(a->f)
+#define wcfread(a,b,c,d) fread(a,b,c,d->f)
+#define wcfwrite(a,b,c,d) fwrite(a,b,c,d->f)
+#define wcftell(a) ftell(a->f)
+#define wcfflush(a) fflush(a->f)
+
+inline int truncate(FILE *f, unsigned long b)
+{
+  return chsize(fileno(f), b);
+}
+
+inline int wctruncate(WCFILE *f, unsigned long b)
+{
+  return chsize(fileno(f->f), b);
+}
+
+#define lock_file(a)  {fflush(a->f);flock(a, 1);}
+#define unlock_file(a)  {fflush(a->f);flock(a, 0);}
+
+#if _DEBUG_ == 1
+
+#include <assert.h>
+
+/* memory leaks detection */
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+
+#endif // _DEBUG_
+
+/**********Unix*********/
+#else
+#include <fcntl.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+
+#define WCFILE FILE
+
+#define wcfopen fopen
+#define wcfclose fclose
+#define wcfseek fseek
+#define wcfeof feof
+#define wcfread fread
+#define wcfwrite fwrite
+#define wcftell ftell
+#define wcfflush fflush
+
+#define lock_file(a)  {fflush(a);flock(fileno(a), LOCK_EX);}
+#define unlock_file(a)  {fflush(a);flock(fileno(a), LOCK_UN);}
+
+//string case-insensitive compare
+#define strcmpi strcasecmp
+
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////// Platform independent MACRO definitions
+///////////////////////////////////////////////////////////////////////////////
+
+#define FILE_ACCESS_MODES_RW  "rb+" // read-write mode
+#define FILE_ACCESS_MODES_R   "rb"  // read mode
+#define FILE_ACCESS_MODES_CW  "wb+" // create new (overwrite)
+
+//  Environment params name
+#define QUERY_STRING  "QUERY_STRING"
+#define REQUEST_URI   "REQUEST_URI"
+#define REMOTE_ADDR   "REMOTE_ADDR"
+
+//  HTML checked or/and selected
+#define RADIO_CHECKED   " CHECKED"
+#define LISTBOX_SELECTED  " SELECTED"
+
+#define fCheckedRead(buffer, size, f) (wcfread(buffer, 1, size, f) == size)
+#define fCheckedWrite(buffer, size, f)  (wcfwrite(buffer, 1, size, f) == size)
+typedef unsigned char BYTE;
+#define M_IN(x,a,b) (((x)>=(a))&&((x)<=(b)))
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////// Internal parameters
+///////////////////////////////////////////////////////////////////////////////
+
+/*---------------------- DIRECTORIES ----------------------*/
+#define DIR_MAINDATA  "data/"
+#define DIR_MESSAGES  DIR_MAINDATA "messages/"      // messages dir, for message database only
+#define DIR_SEARCHER  DIR_MAINDATA "searcher/"      // searcher dir, for search index only
+#define DIR_PROFILES  DIR_MAINDATA "profiles/"      // profiles dir, profile database only
+#define DIR_SETTINGS  DIR_MAINDATA "settings/"      // settings dir, for forum settings
+#define DIR_INTERNALS DIR_MAINDATA "internals/"     // internal settings that will be autocreated
+#define DIR_PROF_PIC  DIR_PROFILES "pic/" // profile pictures dir
+
+/*-------------------- PROFILES DATABASE ------------------*/
+#define F_PROF_INDEX  DIR_PROFILES "profindex.idx"  // profile login indexes
+#define F_PROF_NINDEX DIR_PROFILES "profindex.db"   // profile indexes
+#define F_PROF_FREENIDX DIR_PROFILES "profifree.db"   // profile free nindex indexes
+#define F_PROF_BODY   DIR_PROFILES "profbody.db"    // profile bodies (full user info)
+#define F_PROF_FREEBODY DIR_PROFILES "profbfree.db"   // profile free body indexes
+#define F_PROF_PERSMSG  DIR_PROFILES "profpers.db"    // profile personal messages index
+#define F_PROF_ALTNICK  DIR_PROFILES "profcnicks.db"  // profile alternative nick spelling
+
+/*------------------- CONFIGURATION FILES -----------------*/
+#define F_CONFIG    "wwwconf.conf"    // config file -- NOT YET SUPPORTED
+
+/*------------------ MESSAGE DATABASE FILES ---------------*/
+#define F_MSGINDEX    DIR_MESSAGES "index.msg"      // message headers
+#define F_MSGBODY   DIR_MESSAGES "messages.msg"   // message bodies
+#define F_INDEX     DIR_MESSAGES "ra_index.msg"   // random access index file (hronological indexes)
+#define F_VINDEX    DIR_MESSAGES "vra_index.msg"  // virtual index file
+#define F_FREEMBODY   DIR_MESSAGES "freemess.msg"   // free spaces in message bodies
+#define F_FREEINDEX   DIR_MESSAGES "freeindex.msg"  // free spaces in message headers
+#define F_GLOBAL_ANN  DIR_MESSAGES "globalann.msg"  // global announces
+
+/*------------------ SEARCH INDEX FILES -------------------*/
+#define F_SEARCH_INDEX    DIR_SEARCHER "messearch.idx"  // searcher message index file
+#define F_SEARCH_DB     DIR_SEARCHER "messearch.db"   // searcher message index file
+#define F_SEARCH_LASTINDEX  DIR_SEARCHER "lastindex"    // database id and last indexed message
+
+/*---------------- SETTINGS FILES --------------*/
+#define F_BANNEDIP    DIR_SETTINGS "banned.txt"   // list of banned IP
+#define F_BADWORDS    DIR_SETTINGS "badwords.txt"   // list of words, witch is resstricted message headers and bodies
+
+/*---------------- INTERNAL SUPPORT FILES --------------*/
+#define F_ANTISPAM    DIR_INTERNALS "antispam.dat"    // antispam system file
+#define F_AUTHSEQ   DIR_INTERNALS "authuser.dat"    // currently authorized users (sessions)
+#define F_ACTIVITYLOG1  DIR_INTERNALS "activitylog1.dat"  // user activity log file 1
+#define F_ACTIVITYLOG2  DIR_INTERNALS "activitylog2.dat"  // user activity log file 2
+#define F_ACTIVITYARCH  DIR_INTERNALS "activityarch.dat"  // user activity archive
+
+/*---------------------- LOG FILE -------------------------*/
+#define LOG_FILE    DIR_MAINDATA "wwwconf.log"    // log file
+
+/*------------- BANNERS&HELP (should be placed with index of forum) -------------*/
+#define F_TOPBANNER   "topbanner.html"  // top banner of wwwconf
+#define F_BOTTOMBANNER  "bottombanner.html" // bottom banner of wwwconf
+#define F_FAQ_HELP    "help.html"   // information about using tags and smiles of wwwconf
+#define F_RULES_HELP  "rules.html" // infromation about rules of board
+
+#define COOKIE_MAX_LENGTH     400
+
+#define MAX_STRING 255
+/* maximal parameters string and message length */
+#define MAX_PARAMETERS_STRING 65535
+
+#define DATE_PRINT_STYLE          1
+#define THREAD_PRINT_STYLE          2
+#define SHOW_MESSAGE_STYLE_HRON_FORWARD   1
+#define SHOW_MESSAGE_STYLE_HRON_BACKWARD  2
+
+#define PRINT_FORWARD 1
+#define PRINT_BACKWARD  0
+#define GO_FORWARD    1
+#define GO_BACKWARD   0
+
+/********** bit masks **********/
+/********** Message flags ****************/
+#define MESSAGE_HAVE_PICTURE    0x0001
+#define MESSAGE_HAVE_URL      0x0002
+#define MESSAGE_HAVE_BODY     0x0004
+#define MESSAGE_IS_CLOSED     0x0008
+#define MESSAGE_IS_INVISIBLE    0x0010
+#define MESSAGE_ENABLED_TAGS    0x0020
+#define MESSAGE_ENABLED_SMILES    0x0040  // affects only to HEADER of msg
+#define MESSAGE_MAIL_NOTIFIATION  0x0080
+#define MESSAGE_COLLAPSED_THREAD  0x0100  // collapsed thread
+#define MESSAGE_WAS_SIGNED      0x0200  // message have signature
+#define MESSAGE_ENABLED_HTML    0x0400  // message in html format
+
+/* for printhtmlmessage_in_index proc */
+#define MESSAGE_INDEX_PRINT_ITS_URL   0x0001
+#define MESSAGE_INDEX_DISABLE_ROLLED  0x0002
+#define MESSAGE_INDEX_PRINT_BLANK_URL 0x0004
+
+/* for user right - all modify/close/roll/delete modes affect ONLY on own posts! */
+
+#define USERRIGHT_COUNT   14
+
+#define USERRIGHT_SUPERUSER       0x0001  // allow ALL rigth (skip all right test)
+#define USERRIGHT_VIEW_MESSAGE      0x0002  // allow view messages in conference
+#define USERRIGHT_MODIFY_MESSAGE    0x0004  // modify (change) own messages
+#define USERRIGHT_CLOSE_MESSAGE     0x0008  // close thread right
+#define USERRIGHT_OPEN_MESSAGE      0x0010  // open thread right (form closed)
+#define USERRIGHT_CREATE_MESSAGE    0x0020  // create message (reply)
+#define USERRIGHT_CREATE_MESSAGE_THREAD 0x0040  // create message (new thread)
+#define USERRIGTH_ALLOW_HTML      0x0080  // allow HTML right
+#define USERRIGTH_PROFILE_MODIFY    0x0100  // allow modify, delete own profile
+#define USERRIGTH_PROFILE_CREATE    0x0200  // allow create new profiles
+#define USERRIGHT_ROLL_MESSAGE      0x0400  // roll thread right
+#define USERRIGHT_UNROLL_MESSAGE    0x0800  // unroll thread right
+#define USERRIGHT_POST_GLOBAL_ANNOUNCE  0x1000  // post global conference announce
+#define USERRIGHT_ALT_DISPLAY_NAME    0x2000  // alternative display name
+
+/* for virtual indexes */
+#define NO_MESSAGE_CODE 0xFFFFFFFF
+
+/*  Common message structure */
+struct SMessage
+{
+  /* common parameters */
+  char MessageHeader[MESSAGE_HEADER_LENGTH];
+  char AuthorName[AUTHOR_NAME_LENGTH];
+  char HostName[HOST_NAME_LENGTH];
+
+  /* IP Address of poster */
+  DWORD IPAddr;
+
+  /* unique user ID or 0, if anonymous posts */
+  DWORD UniqUserID;
+
+  /* security level of message (for tags, etc.) */
+  /* body security */
+  BYTE Security;
+  /* header security */
+  BYTE SecHeader;
+
+  /* flag of message : HAVE_PIC, CLOSED, etc. */
+  DWORD Flag;
+
+  /* creation time */
+  time_t Date;
+  /* modifying  date */
+  time_t MDate;
+
+  /* message level in tree */
+  WORD Level;
+
+  /* topic flags */
+  DWORD Topics;
+
+  /* request counter of this message */
+  WORD Readed;
+
+  /* index of main thread message */
+  DWORD ParentThread;
+
+  // ????????????????????????????????????????
+  /* index of parent message
+  DWORD ParentMsg;
+  */
+
+  /* virtual index of message */
+  DWORD ViIndex;
+
+  /* index of message body */
+  DWORD MIndex;
+  /* size of message body */
+  DWORD msize;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////// Subroutine definitions
+///////////////////////////////////////////////////////////////////////////////
+
+char* toupperstr(char *s);
+
+#endif // of BASETYPES_H_INCLUDED
blob - /dev/null
blob + fc51e9f1cf037c23b68ce6e6c4f55231e6e3680b (mode 644)
--- /dev/null
+++ src/boardtags.cpp
@@ -0,0 +1,747 @@
+/***************************************************************************
+                          boardtags.cpp  -  board tags support
+                             -------------------
+    begin                : Sun Apr 29 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "boardtags.h"
+#include "error.h"
+
+/* following define WWWConf Board Tags, and
+ * it's translation into standart HTML tags,
+ * and security level of each tag
+ */
+STagConvert TagConvTable[BoardTagCount] = {
+	/* text output tags */
+	{"B", "<B>", WC_TAG_TYPE_1, "</B>", WC_TAG_TYPE_1, 2},
+	{"E", "<EM>", WC_TAG_TYPE_1, "</EM>", WC_TAG_TYPE_1, 2},
+	{"I", "<I>", WC_TAG_TYPE_1, "</I>", WC_TAG_TYPE_1, 2},
+	{"U", "<U>", WC_TAG_TYPE_1, "</U>", WC_TAG_TYPE_1, 2},
+	{"H", "<B><FONT SIZE=4>", WC_TAG_TYPE_1, "</FONT></B>", WC_TAG_TYPE_1, 0},
+	{"S", "<FONT SIZE=1>", WC_TAG_TYPE_1, "</FONT>", WC_TAG_TYPE_1, 2},
+	/* Colour tags */
+	{"GREEN", "<FONT COLOR=#00FF00>", WC_TAG_TYPE_1, "</FONT>", WC_TAG_TYPE_1, 2},
+	{"RED", "<FONT COLOR=#FF0000>", WC_TAG_TYPE_1, "</FONT>", WC_TAG_TYPE_1, 0},
+	{"COLOR", "<FONT COLOR=%s>", WC_TAG_TYPE_2, "</FONT>", WC_TAG_TYPE_1, 0},
+	{"C", "<FONT COLOR=%s>", WC_TAG_TYPE_2, "</FONT>", WC_TAG_TYPE_1, 0},
+	/* URL, Picture, Mail */
+	{"URL", "<A HREF=\"%s\" STYLE=\"text-decoration:underline;\" TARGET=_blank>", WC_TAG_TYPE_2, "</A>", WC_TAG_TYPE_1, 10},
+	{"PIC", "<IMG src=\"", WC_TAG_TYPE_1, "\">", WC_TAG_TYPE_1, 10},
+	{"MAIL", "<A HREF=\"mailto:%s\" STYLE=\"text-decoration:underline;\">", WC_TAG_TYPE_2, "</A>", WC_TAG_TYPE_1, 10},
+	/* HR SIZE=1 */
+	{"HR", "<HR SIZE=2>", WC_TAG_TYPE_ONLYOPEN, "", WC_TAG_TYPE_DISABLED, 2},
+	/* quotation */
+	{"Q", "<P><B>Quotation:</B><DL><BOLD><FONT COLOR=#222222 SIZE=2><STRONG>", 
+	WC_TAG_TYPE_1, "</STRONG></FONT></BOLD></DL></P>", WC_TAG_TYPE_1, 2},
+	/* Center */
+	{"CENTER", "<CENTER>", WC_TAG_TYPE_1, "</CENTER>", WC_TAG_TYPE_1, 10},
+	/* Pre */
+	{"PRE", "<PRE STYLE=\"margin-left:25px\">", WC_TAG_TYPE_1, "</PRE>", WC_TAG_TYPE_1, 10},
+	{"STRIKE", "<STRIKE>", WC_TAG_TYPE_1, "</STRIKE>", WC_TAG_TYPE_1, 2}
+};
+
+/* define there smile-like codes
+ * and it's translation to HTML
+ * first character in tag must be ':' or ';'
+ */
+SPicConvert PicConvTable[BoardPicCount] = {
+	{":))",		"bigsmile.gif",		9},
+	{":-))",	"bigsmile.gif",		9},
+	{":-)",		"smile.gif",		9},
+	{":)",		"smile.gif",		9},
+	{":(",		"frown.gif",		9},
+	{":-(",		"frown.gif",		9},
+	{";)",		"wink.gif",			9},
+	{";-)",		"wink.gif",			9},
+	{":LOL",	"lol.gif",			9},
+	{":!!",		"lol.gif",			9},
+	{":-\\",	"smirk.gif",		9},
+	{":\\",		"smirk.gif",		9},
+	{":o",		"redface.gif",		9},
+	{":MAD",	"mad.gif",			9},
+	{":STOP",	"stop.gif",			0},	// admin only
+	{":APPL",	"appl.gif",			9},
+	{":BAN",	"ban.gif",			9},
+	{":BEE",	"bee.gif",			9},
+	{":BIS",	"bis.gif",			9},
+	{":ZLOBA",	"blya.gif",			9},
+	{":BORED",	"bored.gif",		9},
+	{":BOTAT",	"botat.gif",		9},
+	{":COMP",	"comp.gif",			9},
+	{":CRAZY",	"crazy.gif",		9},
+	{":DEVIL",	"devil.gif",		9},
+	{":DOWN",	"down.gif",			9},
+	{":FIGA",	"figa.gif",			9},
+	{":GIT",	"git.gif",			9},
+	{":GYGY",	"gy.gif",			9},
+	{":HEH",	"heh.gif",			9},
+	{":CIQ",	"iq.gif",			9},
+	{":KURIT",	"kos.gif",			9},
+	{":LAM",	"lam.gif",			9},
+	{":MNC",	"mnc.gif",			9},
+	{":NO",		"no.gif",			9},
+	{":SMOKE",	"smoke.gif",		9},
+	{":SORRY",	"sorry.gif",		9},
+	{":SUPER",	"super.gif",		9},
+	{":UP",		"up.gif",			9},
+	{":YES2",	"yes2.gif",			9},
+	{":YES",	"yes.gif",			9},
+	{":BASH",	"bash.gif",			9},
+	{":CLAPPY",	"clappy.gif",		9},
+	{":EWW",	"eww.gif",			9},
+	{":ROTFL",	"roflol.gif",		9},
+	{":SPOTMAN","spotman.gif",		9},
+	{":WAVE",	"wave.gif",			9},
+	{":COWARD",	"coward.gif",		9},
+	{":DRAZNIT","draznit.gif",		9},
+	{":ROLLEYES","pizdets.gif",		9},
+	{":PLOHO",	"blevalyanaeto.gif",9},
+	{":}",		"icqbig.gif",		9},
+};
+
+/* parse string to nearest ';' or ':' */
+int inline ParseToOpenSmileTagorHttp(char *s)
+{
+	register unsigned int i = 0;
+#if TRY_AUTO_URL_PREPARSE
+	// find smile, ftp or http start
+	while(s[i] != 0 && s[i] != ':' && s[i] != ';' && s[i] != 'h' && s[i] != 'f') i++;
+#else
+	while(s[i] != 0 && s[i] != ':' && s[i] != ';') i++;
+#endif
+	return i;
+}
+
+#if TRY_AUTO_URL_PREPARSE
+/* return 1 if url was parsed, 0 otherwise */
+static int ReparseUrl(char **ss, char **dd, DWORD status)
+{
+	int rf = 0;
+	char *d = *dd, *s = *ss;
+	int slen = strlen(s);
+	if( ( (slen > 7) && (strncmp(s, "http://", 7) == 0) ) ||
+		( (slen > 8) && (strncmp(s, "https://", 8) == 0) ) ||
+	 	( (slen > 6) && (strncmp(s, "ftp://", 6) == 0) ) )
+	{
+		if((status & 4)) {
+			//	we have found http:// | https:// | ftp:// reference, so try to parse it
+			char *olds = s;
+			char oldcs;
+			char *dtmp;
+
+			if(*s == 'h') s++;
+			s+=6;
+
+			while(*s != 0 && *s != 13 && *s != 10 && *s != ' ' && *s != ')' && *s != '(' 
+				&& *s != '>' && *s != '<' && *s != ']' && *s != '[' && *s != ',' 
+				&& strncmp(s, "&quot;", 6) !=0 ) s++;
+			oldcs = *s;
+			*s = 0;
+			dtmp = (char*)malloc(strlen(olds)*2+strlen(PARSED_URL_TMPL));
+			sprintf(dtmp, PARSED_URL_TMPL, olds, olds);
+			strcpy(d, dtmp);
+			d+=strlen(dtmp);
+			free(dtmp);
+			*s = oldcs;
+		}
+		rf = 1;
+	}
+
+	*dd = d;
+	*ss = s;
+	return rf;
+}
+#endif
+
+/* Smart strcat() function. It removes all duplicated spaces, char #10 and all tabs.
+ * The behavior depends of status. If status nonzero it works as usual strcat except
+ * #10 char removing.
+ * status meaning:
+ *		0x01 - spaces and tabs elimination (DISABLING)
+ *		0x02 - 13 -> BR parsing
+ *		0x04 - url parsing
+ */
+int inline smartstrcat(char *d, char *s, DWORD status, DWORD *flg)
+{
+	char *od = d;
+	int fstat;
+	d += strlen(d);
+	*flg = 0;
+	if(status & 1) {
+		while(*s != 0) {
+#if TRY_AUTO_URL_PREPARSE
+			fstat = ReparseUrl(&s, &d, status);
+			if(fstat) *flg = 1;
+#endif
+
+			if(*s != 10) {
+				if(*s == 13 && (status & 2)) {
+					// convert to <BR>
+					memcpy(d, "<BR>", 4);
+					d+=4;
+				}
+				else {
+					*d = *s;
+					d++;
+				}
+			}
+			s++;
+		}
+		*d = *s;
+	}
+	else {
+		register int ws = 0; // was space or tab
+		while(*s != 0) {
+#if TRY_AUTO_URL_PREPARSE
+			fstat = ReparseUrl(&s, &d, status);
+			if(fstat) *flg = 1;
+#endif
+
+			if( *s != 10 && (!(ws && (*s == 0x20 || *s == 0x09))) ) {
+				if(*s == 0x20 || *s == 0x09) {
+					ws = 1;
+					*d = 0x20; // space
+				}
+				else {
+					ws = 0;
+					if(*s == 13 && (status & 2)) {
+						// convert to <BR>
+						memcpy(d, "<BR>", 4);
+						d+=3;
+					}
+					else *d = *s;
+				}
+				d++;
+			}
+			s++;
+		}
+		*d = *s;
+	}
+	return d - od;
+}
+
+/* function for concatenation string s to d
+ * with converting smile-codes to images
+ */
+int inline ParseSmiles_smartstrcat(char *d, char *s, BYTE sec, DWORD status, DWORD *flg)
+{
+	register char *dd = d + strlen(d);
+	register char *ss = s;
+	unsigned int i = 0, fstat;
+	int wassmile = 0;
+	*flg = 0;
+	while(*ss != 0) {
+		i = ParseToOpenSmileTagorHttp(ss);
+		if(i) {
+			char si = ss[i];
+			ss[i] = 0;
+			dd += smartstrcat(dd, ss, status, flg);
+			ss[i] = si;
+			ss += i;
+		}
+		if(*ss == 0) break;
+
+#if TRY_AUTO_URL_PREPARSE
+		fstat = ReparseUrl(&ss, &dd, status);
+		if(fstat) *flg = 1;
+#endif
+
+		for(register unsigned int j = 0; j < BoardPicCount; j++) {
+			if(strlen(PicConvTable[j].tag) <= strlen(ss) && PicConvTable[j].security >= sec &&
+				strncmp(ss, PicConvTable[j].tag, strlen(PicConvTable[j].tag)) == 0 && ((status & 1) == 0) ) {
+				wassmile = 1;
+				strcat(dd, "<IMG BORDER=0 SRC=\"" BOARD_PIC_URL);
+				strcat(dd, PicConvTable[j].url);
+				strcat(dd, "\" ALT=\"");
+				strcat(dd, PicConvTable[j].tag);
+				strcat(dd, "\">");
+				dd += strlen(dd);
+				ss += strlen(PicConvTable[j].tag);
+				goto next_sym;
+			}
+		}
+
+		if(*dd == 0) *(dd+1) = 0;
+
+		if(*ss == 13 && (status & 2)) {
+			// convert to <BR>
+			memcpy(dd, "<BR>", 4);
+			dd+=3;
+		}
+		else {
+			*dd = *ss;
+		}
+		dd++;
+		ss++;
+next_sym: ;
+	}
+	*dd = 0;
+	return wassmile;
+}
+
+/* insert string s to string d at position index
+ * return d, DOES NOT CONTROL ANY ERRORS
+ */
+char* strins(char *d, char *s, int index)
+{
+	register char *p = d + index; // from
+	register char *t = d + index + strlen(s); // to
+	register unsigned int x = strlen(d) - index; // count
+	for(register int j = x; j >= 0; j--) t[j] = p[j];
+	t[x+1] = 0;
+	strncpy(p, s, strlen(s));
+	return d;
+	
+}
+
+/* parse string up to nearest =, WC_TAG_OPEN/CLOSE */
+int inline ParseRegExp(char *s)
+{
+	register int i = 0;
+	while(s[i] != 0 && s[i] != '=' && s[i] != WC_TAG_CLOSE && s[i] != WC_TAG_OPEN) i++;
+	return i;
+}
+
+/* parse to nearest WC_TAG_OPEN */
+int inline ParseToOpenWC_TAG(char *s)
+{
+	register int i = 0;
+	while(s[i] != 0 && s[i] != WC_TAG_OPEN) i++;
+	return i;
+}
+
+/* parse to nearest WC_TAG_CLOSE */
+int inline ParseToCloseWC_TAG(char *s)
+{
+	register int i = 0;
+	while(s[i] != 0 && s[i] != WC_TAG_CLOSE) i++;
+	return i;
+}
+
+/* input:	s - parsing string with begining of tag (first symbol = WC_TAG_OPEN)
+ * oputput: function return length of parsed board tag or 0 if tag is not valid
+ *				par1 - tag name, par2 - parameter after = in tag (NULL if not present)
+ */
+int inline ParseBoardTag(char *s, char **par1, char **par2)
+{
+	char *ss;
+	int i, j;
+	ss = s;
+	*par1 = NULL;
+	*par2 = NULL;
+	// ignore WC_TAG_OPEN
+	if(*s != WC_TAG_OPEN) {
+		return 0;
+	}
+	s++;
+	// parse first arg
+	i = ParseRegExp(s);
+	if(i == 0) {
+		return 0;
+	}
+	*par1=(char*)malloc(i + 1);
+	char ts = s[i];
+	s[i] = 0;
+	strcpy(*par1, s);
+	toupperstr(*par1);
+	s[i] = ts;
+	s += i;
+	if(*s == WC_TAG_CLOSE) {
+		return s - ss + 1;
+	}
+	if(*s == '=') {
+		// parse second arg
+		s++;
+		j = ParseToCloseWC_TAG(s);
+		if(j == 0) {
+			goto ParseBoardTag_Faild;
+		}
+		if(s[j] == WC_TAG_CLOSE) {
+			*par2=(char*)malloc(j + 1);
+			char ts = s[j];
+			s[j] = 0;
+			strcpy(*par2, s);
+			s[j] = ts;
+			return s - ss + j + 1;
+		}
+	}
+ParseBoardTag_Faild:
+	free(*par1);
+	*par1 = NULL;
+	*par2 = NULL;
+	return 0;
+}
+
+/* check and expand board tags -> HTML tags
+ * return value: function return 1 if successfull, overwise 0
+ * tagtype - tag type (index in TagConvTable) and taglen = 1, 2 
+ */
+int inline ExpandTag(char *tag1, char *tag2, char **restag, int *tagnumber, int *tagtype, BYTE security)
+{
+	int tagdirection = 0; /* open by default */
+	
+	if(tag1[0] == '/')  {
+		tagdirection = 1;
+		tag1++;
+	}
+	
+	*restag = NULL;
+	
+	for(int i=0; i < BoardTagCount; i++) {
+		if(strcmp(tag1, TagConvTable[i].tag) == 0) {
+			if(TagConvTable[i].security < security) {
+				return 0;
+			}
+			*tagnumber = i;
+			int tagt;
+			if(tagdirection) tagt = TagConvTable[i].typeclose;
+			else tagt = TagConvTable[i].typeopen;
+			switch(tagt) {
+			case WC_TAG_TYPE_1:
+				*tagtype = WC_TAG_TYPE_1;
+				/* check for valid param count */
+				if(tag2 != NULL) return 0;
+				if(tagdirection) {
+					/* closing */
+					*restag = (char*)malloc(strlen(TagConvTable[i].tclosetag) + 1);
+					strcpy(*restag, TagConvTable[i].tclosetag);
+				}
+				else {
+					/* opening */
+					*restag = (char*)malloc(strlen(TagConvTable[i].topentag) + 1);
+					strcpy(*restag, TagConvTable[i].topentag);
+				}
+				return 1;
+				
+			case WC_TAG_TYPE_2:
+				*tagtype = WC_TAG_TYPE_2;
+				/* check for valid param count
+				*/
+				if(tag2 == NULL) return 0;
+				if(!tagdirection) {
+					/* opening */
+					char *parsedtag2;
+
+					if(i == URL_TAG_TYPE) {
+						if(strncmp(tag2, "http:", 5) != 0 && strncmp(tag2, "ftp:", 4) != 0 &&
+						    strncmp(tag2, "file:", 5) != 0 && strncmp(tag2, "https:", 6) != 0 &&
+							strncmp(tag2, "smb:", 6) != 0)
+						{
+							parsedtag2 = (char*)malloc(strlen(tag2) + 10);
+							strcpy(parsedtag2, "http://");
+							strcat(parsedtag2, tag2);
+						}
+						else parsedtag2 = tag2;
+					}
+					else parsedtag2 = tag2;
+
+					*restag = (char*)malloc(strlen(TagConvTable[i].topentag) + 1 + strlen(parsedtag2));
+
+					/* use sprintf() to insert tag2 into result
+					 * (format of topentag as %s instead of tag2)
+					 */
+					sprintf(*restag, TagConvTable[i].topentag, parsedtag2);
+					*restag = (char*)realloc(*restag, strlen(*restag) + 1);
+					if(parsedtag2 != tag2) free(parsedtag2);
+				}
+				else {
+					/* closing - not currently supported */
+					return 0;
+				}
+				return 1;
+				
+			case WC_TAG_TYPE_12:
+				/* temporary not used */
+				
+				return 0;
+				
+			case WC_TAG_TYPE_ONLYOPEN:
+				*tagtype = WC_TAG_TYPE_ONLYOPEN;
+				/* check for valid param count
+				*/
+				if(tag2 != NULL) return 0;
+				if(!tagdirection) {
+					/* opening */
+					*restag = (char*)malloc(strlen(TagConvTable[i].topentag) + 1);
+					strcpy(*restag, TagConvTable[i].topentag);
+				}
+				else {
+					/* closing - not valid (only opening) */
+					return 0;
+				}
+				return 1;
+			}
+		}
+	}
+	/* tag not found */
+	return 0;
+}
+
+/* filtering smile codes and board tags using current security level = security
+ * and message flags MESSAGE_ENABLED_SMILES MESSAGE_ENABLED_TAGS
+ * return value 1 if all successfull, or 0 if string was cutted, 
+ * because of ml limitation
+ * **** input : s - string, ml - max result string length, Flags - flags of message, security - sec.
+ * level of msg (for tags conversion)
+ * **** output : r - resulting string
+
+ *	Meaning of some flags
+ *		0x80 - set up flag HAVE_URL
+ *		0x04 - url autopreparse
+
+ */
+int FilterBoardTags(char *s, char **r, BYTE security, DWORD ml, DWORD Flags, DWORD *RF)
+{
+	//
+	int beforePreStatus;
+	//
+	char *tag1 = NULL, *tag2 = NULL, *res = NULL, *st;
+	DWORD opentag, reff, status = 0x04, urldisable = 0;	// http preparse
+	int i, StringTooLong = 0;
+	SSavedTag OldTag[MAX_NESTED_TAGS];
+	
+	// ignore starting newline
+	while(*s == 10 || *s == 13) s++;
+	
+	// ignore ending newline
+	{
+		int sl = strlen(s);
+		register int k;
+		for(k = sl; k>0; k--) {
+			if(!(s[k - 1] == 10 || s[k - 1] == 13))
+				break;
+		}
+		s[k] = 0;
+	}
+
+	*RF = 0;
+	*r = NULL;
+
+	if(Flags & BOARDTAGS_EXPAND_ENTER)
+		status |= 0x02;	// 13 -> <BR> conversion
+
+	if((Flags & BOARDTAGS_CUT_TAGS) || (Flags & BOARDTAGS_TAG_PREPARSE) || ((Flags & BOARDTAGS_PURL_ENABLE) == 0)) {
+		status &= (~0x04);	// disable url parsing
+		urldisable = 1;
+	}
+
+	/* alloc memory for resulting string */
+	beforePreStatus = status;
+	if(ml < 32000) st = (char *)malloc(32000);
+	else st = (char *)malloc(3*ml);
+
+	st[0] = 0;
+	opentag = 0;
+	for(;;) {
+		if(strlen(st) >= ml) {
+			StringTooLong = 1;
+			break;
+		}
+		if(*s == 0) break;
+		i = ParseToOpenWC_TAG(s);
+		if(i) {
+			char si = s[i];
+			s[i] = 0;
+			if((Flags & MESSAGE_ENABLED_SMILES) && ((Flags & BOARDTAGS_TAG_PREPARSE) == 0)) {
+				if(ParseSmiles_smartstrcat(st, s, security, status, &reff)) {
+					*RF = *RF | MESSAGE_ENABLED_SMILES;
+				}
+				if(reff && ((status & 0x80) == 0)) (*RF) |= MESSAGE_HAVE_URL;
+			}
+			else {
+				smartstrcat(st, s, status, &reff);
+				if(reff && ((status & 0x80) == 0)) (*RF) |= MESSAGE_HAVE_URL;
+			}
+			s[i] = si;
+			s += i;
+		}
+		i = ParseBoardTag(s, &tag1, &tag2);
+
+		if((Flags & MESSAGE_ENABLED_TAGS) == 0)
+			goto ignore_tag;
+
+		if(i) {
+			int tt = 0, tl = 0;
+
+			/* we have tag, parse  it! */
+			if(!ExpandTag(tag1, tag2, &res, &tt, &tl, security)) {
+				/* invalid tag */
+				goto ignore_tag;
+			}
+
+			if(tl == WC_TAG_TYPE_ONLYOPEN) {
+				*RF = *RF | MESSAGE_ENABLED_TAGS;
+				if((status & 1) == 0 && ((Flags & BOARDTAGS_TAG_PREPARSE) == 0)) {
+					// only opened tag - so parse it at once
+					strcat(st, res);
+					s += i;
+				}
+				else goto ignore_tag;
+			}
+			else {
+				// if successfully expanded (exists)
+				// already have open tag - so try to interpret it as closing tag
+				if(tag1[0] == '/') {
+					if(opentag) {
+						/* closing tag - check for conformity */
+						if( tl != 1 || OldTag[opentag - 1].tt != tt) {
+							/* incompartable tags - ignore it */
+							goto ignore_tag;
+						}
+
+						if(tt == PRE_TAG_TYPE || tt == PIC_TAG_TYPE) // allow tag and space parsing again
+							status &= 0xFFFFFFFE;
+						if(tt == PRE_TAG_TYPE)
+							status = beforePreStatus;
+						/* set flags of message type */
+						if(tt == PIC_TAG_TYPE) { /* there was a picture tag */
+							if(!urldisable) {
+								status |= 0x04;	// allow http parsing
+							}
+							status &= (~0x80);
+							*RF = *RF | MESSAGE_HAVE_PICTURE;
+						}
+						if(tt == URL_TAG_TYPE) { /* there was a url tag */
+							if(!urldisable) {
+								status |= 0x04;	// allow http parsing
+							}
+							*RF = *RF | MESSAGE_HAVE_URL;
+						}
+						/* have at least one tag */
+						*RF = *RF | MESSAGE_ENABLED_TAGS;
+
+						//	what we will do with tags
+						if((Flags & BOARDTAGS_TAG_PREPARSE)) {
+							// do not change tags, just preparse spaces, etc.
+							strins(st, OldTag[opentag - 1].oldexp, OldTag[opentag - 1].index);
+							char os = s[i];
+							s[i] = 0;
+							strcat(st, s);
+							s[i] = os;
+						}
+						else {
+							// expand tags or ignore(cut) them
+							if((Flags & BOARDTAGS_CUT_TAGS) == 0) {
+								//
+								//	PATCH for PIC tag
+								//
+								if(tt == PIC_TAG_TYPE) { /* there was a picture tag */
+									char *ts = st + OldTag[opentag - 1].index;
+									if(strncmp(ts, "http:", 5) != 0 && strncmp(ts, "ftp:", 4) != 0 &&
+									   strncmp(ts, "file:", 5) != 0 && strncmp(ts, "https:", 6) != 0 &&
+									   strncmp(ts, "smb:", 6) != 0)
+									{
+										// add http
+										strins(ts, "http://", 0);
+									}
+								}
+								strins(st, OldTag[opentag - 1].tagexp, OldTag[opentag - 1].index);
+								strins(st, res, strlen(st));
+							}
+							else {} // tag will be cutted
+						}
+						free(OldTag[opentag - 1].tagexp);
+						free(OldTag[opentag - 1].oldexp);
+						opentag--; // dec tag count
+						s += i;
+					}
+					else {
+						/* ignore tags first elem of tag */
+						goto ignore_tag;
+					}
+				}
+				else {
+					if((status & 1) == 0) {
+						// opening tag
+						/* tag expanded successfully - set current tag struct */
+						if(opentag > MAX_NESTED_TAGS - 1) goto ignore_tag;
+						OldTag[opentag].tt = tt;
+						OldTag[opentag].tl = tl;
+						OldTag[opentag].tagexp = res;
+						res = NULL;
+						OldTag[opentag].index = strlen(st);
+						char os = s[i];
+						s[i] = 0;
+						OldTag[opentag].oldexp = (char*)malloc(strlen(s) + 1);
+						strcpy(OldTag[opentag].oldexp, s);
+						s[i] = os;
+						s += i;
+						opentag++; // inc tag count
+						// check if it was PRE or PIC tag
+						if(tt == PRE_TAG_TYPE) {
+							beforePreStatus = status;
+							status &= ~2;//disable "\n" -> "<br>" conv
+						}
+						if(tt == PRE_TAG_TYPE || tt == PIC_TAG_TYPE) // disable tag parsing
+							status |= 0x01;
+						// check if it was PIC tag
+						if(tt == PIC_TAG_TYPE) {// disable http parsing
+							if(!urldisable)
+								status &= (~0x04);
+							status |= 0x80;
+						}
+						// check if it was URL tag
+						if(tt == URL_TAG_TYPE) {// disable http parsing
+							if(!urldisable)
+								status &= (~0x04);
+						}
+					}
+					else goto ignore_tag;
+				}
+			}
+		}
+		else {
+			/* ignore tags first elem of tag */
+			goto ignore_tag;
+		}
+		goto parse_next;
+ignore_tag:
+		if((*s) != 0) {
+			register char si;
+			si = *(s + 1);
+			*(s +1 ) = 0;
+			strcat(st, s);
+			*(s + 1) = si;
+			s++;
+		}
+parse_next:
+		if(tag1) {
+			free(tag1);
+			tag1 = NULL;
+		}
+		if(tag2) {
+			free(tag2);
+			tag2 = NULL;
+		}
+		if(res) {
+			free(res);
+			res = NULL;
+		}
+	}
+
+	if(StringTooLong) {
+		/* too long string */
+		free(st);
+		for(register DWORD i = 0; i<opentag; i++) {
+			free(OldTag[i].oldexp);
+			free(OldTag[i].tagexp);
+		}
+		return 0;
+	}
+	if(opentag) {
+		register DWORD k;
+		for(k = opentag; k > 0; k--)
+			strins(st, OldTag[k - 1].oldexp, OldTag[k - 1].index);
+
+		for(k = 0; k < opentag; k++) {
+			free(OldTag[k].oldexp);
+			free(OldTag[k].tagexp);
+		}
+	}
+	st = (char*)realloc(st, strlen(st) + 5);
+	*r = st;
+	return 1;
+}
blob - /dev/null
blob + 6f47900bdf178b0cbf65b799fa8c4f486434e241 (mode 644)
--- /dev/null
+++ src/boardtags.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+                          boardtags.h  -  board tags support include
+                             -------------------
+    begin                : Sun Apr 29 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef BOARDTAGS_H_INCLUDED
+#define BOARDTAGS_H_INCLUDED
+
+#include "basetypes.h"
+
+#define WC_TAG_OPEN	'['
+#define WC_TAG_CLOSE	']'
+
+#define TRY_AUTO_URL_PREPARSE	1
+#define PARSED_URL_TMPL		"<A HREF=\"%s\" STYLE=\"text-decoration:underline;\" TARGET=_blank>%s</A>"
+
+#define MAX_NESTED_TAGS			8
+
+#define BOARDTAGS_CUT_TAGS		0x08000000
+#define BOARDTAGS_TAG_PREPARSE	0x10000000
+#define BOARDTAGS_EXPAND_ENTER	0x20000000
+#define BOARDTAGS_PURL_ENABLE	0x40000000
+
+#define BoardTagCount 18
+#define BoardPicCount 52
+
+#define URL_TAG_TYPE 10
+#define PIC_TAG_TYPE 11
+#define PRE_TAG_TYPE 16
+
+#define WC_TAG_TYPE_DISABLED	0
+#define WC_TAG_TYPE_1			1
+#define WC_TAG_TYPE_2			2
+#define WC_TAG_TYPE_12			3
+#define WC_TAG_TYPE_ONLYOPEN	4
+
+/* element of table for converting WWWConf Tags to HTML */
+struct STagConvert {
+	/* board tag */
+	char *tag;
+	/* corresponding opening and closing HTML tags */
+	char *topentag;
+	char typeopen;
+	char *tclosetag;
+	char typeclose;
+	/* security level of tag
+	 * zero - is highest level
+	 */
+	BYTE security;
+};
+
+struct SPicConvert {
+	/* board code */
+	char *tag;
+	/* Pic URL */
+	char *url;
+	/* security level of smile
+	 * zero - is highest level
+	 */
+	BYTE security;
+};
+
+/* Struct for saving last opened tag */
+struct SSavedTag {
+	/* tag type and tag length */
+	int tt, tl;
+	
+	/* tag old and expanded expression */
+	char *tagexp;
+	char *oldexp;
+	/* insert expanded expression index */
+	int index;
+};
+
+int FilterBoardTags(char *s, char **r, BYTE security, DWORD ml, DWORD Flags, DWORD *RF);
+
+#endif
blob - /dev/null
blob + 376771684820314e4e36fee9d2bcac7fa2fc1a71 (mode 644)
--- /dev/null
+++ src/colornick.cpp
@@ -0,0 +1,179 @@
+/***************************************************************************
+                     colornick.cpp  -  alternative nick spelling support
+                             -------------------
+    begin                : Sat Jun 07 2003
+    copyright            : (C) 2001-2003 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "colornick.h"
+
+CAltNamesParser::CAltNamesParser(char *fname, bool &init)
+{
+	init = 0;
+	classinit = 0;
+	AltNamesStruct ns;
+	char *ts;
+	DWORD rd;
+
+	// try to open existing file
+	if((f = wcfopen(fname, FILE_ACCESS_MODES_RW)) == NULL) {
+		// not exist - try to create file
+		if((f = wcfopen(fname, FILE_ACCESS_MODES_CW)) == NULL) {
+			return;
+		}
+		else {
+			wcfclose(f);
+			if((f = wcfopen(fname, FILE_ACCESS_MODES_RW)) == NULL) {
+				return;
+			}
+		}
+	}
+
+	// file successfully opened - read values
+	while(!wcfeof(f)) {
+		if(((rd = (DWORD)wcfread(&ns, 1, sizeof(ns), f)) % sizeof(ns)) != 0) {
+			wcfclose(f);
+			return;
+		}
+		if(!rd) break;
+		ts = (char*)malloc(MAX_ALT_NICK_SIZE);
+		strcpy(ts, ns.aname);
+		nmap[ns.uid] = ts;
+	}
+	wcfclose(f);
+
+	strcpy(ifname, fname);
+
+	init = 1;
+	classinit = 1;
+}
+
+CAltNamesParser::~CAltNamesParser()
+{
+	std::hash_map<DWORD, char*>::iterator it;
+	for(it = nmap.begin(); it != nmap.end(); it++) {
+		free(it->second);
+	}
+	nmap.clear();
+}
+
+int CAltNamesParser::AddAltName(DWORD uid, char *name, char *altname)
+{
+	if(classinit) {
+		if(nmap.find(uid) == nmap.end()) {
+			AltNamesStruct ns;
+			memset(&ns, 0, sizeof(ns));
+			char *s2 = (char*)malloc(MAX_ALT_NICK_SIZE);
+			strcpy(s2, altname);
+			nmap[uid] = s2;
+			// save to file
+			ns.uid = uid;
+			strcpy(ns.rname, name);
+			strcpy(ns.aname, s2);
+			if((f = wcfopen(ifname, FILE_ACCESS_MODES_RW)) == NULL)
+				return 0; 	// file MUST exist
+			lock_file(f);
+			wcfseek(f, 0, SEEK_END);
+			fCheckedWrite(&ns, sizeof(ns), f);
+			unlock_file(f);
+			wcfclose(f);
+			return 1;
+		}
+		else {
+			// update
+			AltNamesStruct ns;
+			memset(&ns, 0, sizeof(ns));
+			DWORD pos, fn = 0;
+			char *s1, *s2 = (char*)malloc(MAX_ALT_NICK_SIZE);
+			strcpy(s2, altname);
+			s1 = nmap[uid];
+			free(s1);
+			nmap[uid] = s2;
+			// save to file (first of all - let's find)
+			if((f = wcfopen(ifname, FILE_ACCESS_MODES_RW)) == NULL)
+				return 0; 	// file MUST exist
+			lock_file(f);
+			while(!wcfeof(f)) {
+				pos = wcftell(f);
+				if(!fCheckedRead(&ns, sizeof(ns), f)) {
+					wcfclose(f);
+					return 0;
+				}
+				if(ns.uid == uid) {
+					strcpy(ns.rname, name);
+					strcpy(ns.aname, altname);
+					wcfseek(f, pos, SEEK_SET);
+					fn = 1;
+					break;
+				}
+			}
+			if(fn) fCheckedWrite(&ns, sizeof(ns), f);
+			unlock_file(f);
+			wcfclose(f);
+			return 1;
+		}
+	}
+	return 0;	// Already exist
+}
+
+int CAltNamesParser::DeleteAltName(DWORD uid)
+{
+	if(classinit) {
+		std::hash_map<DWORD, char*>::iterator it;
+		if(nmap.find(uid) != nmap.end()) {
+			AltNamesStruct ns;
+			DWORD pos, rd, fn = 0;
+			char cb[100000];
+			// delete from file (first of all - let's find)
+			if((f = wcfopen(ifname, FILE_ACCESS_MODES_RW)) == NULL)
+				return 0; 	// file MUST exist
+			lock_file(f);
+			while(!wcfeof(f)) {
+				pos = wcftell(f);
+				if(!fCheckedRead(&ns, sizeof(ns), f)) {
+					wcfclose(f);
+					return 0;
+				}
+				if(ns.uid == uid) {
+					rd = (DWORD)wcfread(cb, 1, 100000, f);
+					if(rd == 100000) {
+						wcfclose(f);
+						return 0;
+					}
+					wcfseek(f, pos, SEEK_SET);
+					fn = 1;
+					break;
+				}
+			}
+			if(fn) fCheckedWrite(cb, rd, f);
+			pos = wcftell(f);
+#ifdef WIN32	
+			wctruncate(f, pos);
+#else
+			truncate(ifname, pos);
+#endif
+			unlock_file(f);
+			wcfclose(f);
+		
+			it = nmap.find(uid);
+			free(it->second);
+			nmap.erase(it);
+
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int CAltNamesParser::NameToAltName(DWORD uid, char *altname)
+{
+	if(classinit) {
+		if(nmap.find(uid) != nmap.end()) {
+			strcpy(altname, nmap[uid]);
+			return 1;
+		}
+	}
+	return 0;
+}
blob - /dev/null
blob + cefae2d1a431b4824fedd926b78ab92c4ed7bae3 (mode 644)
--- /dev/null
+++ src/colornick.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+               colornick.h  -  alternative nick spelling support include
+                             -------------------
+    begin                : Sat Jun 07 2003
+    copyright            : (C) 2001-2003 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef COLORNICK_H_INCLUDED
+#define COLORNICK_H_INCLUDED
+
+#include "basetypes.h"
+
+#if defined(__GNUC__)
+#  if __GNUC__ < 3 && __GNUC__ >= 2 && __GNUC_MINOR__ >= 95
+#     include <hash_map>
+#  elif __GNUC__ >= 3
+#     include <ext/hash_map>
+namespace std{
+	using namespace __gnu_cxx;
+}
+#  else
+#     include <hash_map.h>
+#  endif
+#elif defined(_MSC_VER)
+#  if _MSC_VER >= 1100
+#     include <hash_map>
+#  else
+#     error "std::hash_map is not available with this compiler, compile using MSVC7 and later"
+#  endif
+#elif defined(__sgi__)
+#  include <hash_map>
+#else
+#  error "std::hash_map is not available with this compiler"
+#endif
+
+#define MAX_REAL_NICK_SIZE	30
+#define MAX_ALT_NICK_SIZE	300
+
+class CAltNamesParser {
+private:
+	int classinit;
+	WCFILE *f;
+	char ifname[1000];
+	std::hash_map<DWORD, char*> nmap;
+#pragma pack(1)
+	typedef struct _AltNamesStruct {
+		DWORD uid;
+		char rname[MAX_REAL_NICK_SIZE];
+		char aname[MAX_ALT_NICK_SIZE];
+	} AltNamesStruct, *PAltNamesStruct;
+#pragma pack(4)
+public:
+	CAltNamesParser(char *fname, bool &init);
+	~CAltNamesParser();
+
+	int AddAltName(DWORD uid, char *name, char *altname);
+	int DeleteAltName(DWORD uid);
+	int NameToAltName(DWORD uid, char *altname);
+};
+
+#endif
blob - /dev/null
blob + b8c217849812caef063248628fa2d32b094dad58 (mode 644)
--- /dev/null
+++ src/dbase.cpp
@@ -0,0 +1,3244 @@
+/***************************************************************************
+			     dbase.cpp  -  database message engine
+				-------------------
+	begin                : Wed Mar 14 2001
+	copyright            : (C) 2001 by Alexander Bilichenko
+	email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "dbase.h"
+#include "error.h"
+#include "security.h"
+#include "speller.h"
+#include "messages.h"
+#include "boardtags.h"
+#include "profiles.h"
+#include "freedb.h"
+#include "sendmail.h"
+#include "main.h"
+#include "messages.h"
+
+static int curcolor = 1;
+
+
+// current message displaying parameters
+time_t RefreshDate;
+int currentlsel;
+int currenttc;
+int currenttt;
+int currenttv;
+int currentss;
+int currentdsm;
+DWORD currenttopics;
+int currentlm;
+int currentfm;
+int currentlt;
+int currentft;
+int currentlann;
+int topicsoverride;
+int currenttz;
+
+int cookie_lsel;
+int cookie_tc;
+int cookie_tt;
+int cookie_tv;
+int cookie_ss;
+int cookie_dsm;
+DWORD cookie_topics;
+int cookie_tz;
+
+DWORD cookie_lastenter;
+char *cookie_seq;
+char *cookie_name;
+
+time_t current_minprntime;
+
+CUserLogin ULogin;
+
+#if USER_ALT_NICK_SPELLING_SUPPORT
+static bool cninit;
+CAltNamesParser AltNames(F_PROF_ALTNICK, cninit);
+#endif
+
+int HPrinted = 0;
+
+char *Cip;
+DWORD Nip = 0;
+#if ALLOW_MARK_NEW_MESSAGES == 2
+DWORD newhref = 0;
+#endif
+
+char DESIGN_open_dl[10];
+char DESIGN_open_dl_grey[20];
+char DESIGN_open_dl_white[20];
+char DESIGN_close_dl[10];
+char DESIGN_threads_divider[500];
+char DESIGN_break[10];
+
+int ReadDBMessage(DWORD midx, SMessage *mes)
+{
+	WCFILE *f;
+
+	if(midx == NO_MESSAGE_CODE) return 0;
+	if((f = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_R)) == NULL) return 0;
+	if(wcfseek(f, midx, SEEK_SET) != 0)
+	{
+		wcfclose(f);
+		return 0;
+	}
+	if(!fCheckedRead(mes, sizeof(SMessage), f))
+	{
+		wcfclose(f);
+		return 0;
+	}
+	wcfclose(f);
+	return 1;
+}
+
+int ReadDBMessageBody(char *buf, DWORD index, int size)
+{
+	FILE *f;
+	if((f = fopen(F_MSGBODY, FILE_ACCESS_MODES_R)) == NULL)return 0;
+	if(fseek(f, index, SEEK_SET) != 0) return 0;
+	if(fread(buf, 1, size, f) != size) return 0;
+	fclose(f);
+	return 1;
+}
+
+int WriteDBMessage(DWORD midx, SMessage *mes)
+{
+	WCFILE *f;
+	
+	if((f = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_RW)) == NULL) return 0;
+	lock_file(f);
+	if(wcfseek(f, midx, SEEK_SET) != 0)
+	{
+		unlock_file(f);
+		wcfclose(f);
+		return 0;
+	}
+	if(!fCheckedWrite(mes, sizeof(SMessage), f))
+	{
+		unlock_file(f);
+		wcfclose(f);
+		return 0;
+	}
+	unlock_file(f);
+	wcfclose(f);
+	return 1;
+}
+
+int IP2HostName(DWORD IP, char *hostname, int maxlen)
+{
+	struct hostent *he;
+#if IP_TO_HOSTNAME_RESOLVE
+	//
+	//	Resolve IP to DNS names
+	//
+	if((he = gethostbyaddr((char*)(&IP), 4, AF_INET)) != NULL) {
+		// prevent saving bad hostname
+		if(strlen(he->h_name) > 0) {
+			strncpy(hostname, he->h_name, maxlen);
+
+            if(!strcmp(he->h_name, "veles-1.dipcompany.mipt.ru"))
+                strcpy(hostname, "work.box");
+
+			if(!strcmp(he->h_name, "sipa.4ka.mipt.ru"))
+			    strcpy(hostname, "схухьюЄшъ.4ka.mipt.ru");
+											
+			if(!strcmp(he->h_name, "mc.3ka.mipt.ru"))
+				strcpy(hostname, "votalka.mc");
+				
+			if(!strcmp(he->h_name, "flower.4ka.private.mipt.ru"))
+				strcpy(hostname, "viento.4ka.private.mipt.ru");
+				
+			if(!strcmp(he->h_name, "windmill.dgap.mipt.ru"))
+				strcpy(hostname, "rew24dollar.dgap.mipt.ru");	
+
+
+            if(!strcmp(he->h_name, "172.16.2.124"))
+                strcpy(hostname, "elmariachi.private.rt.mipt.ru");
+
+			if(!strcmp(he->h_name, "energy.3ka.mipt.ru"))
+			strcpy(hostname, "bahus.org");
+											
+		}
+		else return 0;
+	}
+	else return 0;
+#else
+	strcpy(hostname, inet_ntoa(IP), maxlen);
+#endif
+	hostname[maxlen - 1] = 0;
+	return 1;
+}
+
+int ConvertTime(time_t tt, char *s)
+{
+	tt = tt + 3600*(currenttz - DATETIME_DEFAULT_TIMEZONE);
+
+#if DATETIME_STYLE == 1
+	char *c = ctime(&tt);
+	strcpy(s,c);
+	s[strlen(s)-1] = 0;
+#endif
+#if DATETIME_STYLE == 2
+	tm *x;
+	x = localtime(&tt);
+	if(x->tm_min < 10)
+		sprintf(s, "%d/%d/%d %d:0%d", x->tm_mon + 1, x->tm_mday, x->tm_year + 1900,
+		x->tm_hour, x->tm_min);
+	else
+		sprintf(s, "%d/%d/%d %d:%d", x->tm_mon + 1, x->tm_mday, x->tm_year + 1900,
+		x->tm_hour, x->tm_min);
+#endif
+#if DATETIME_STYLE == 3
+	tm *x;
+	x = localtime(&tt);
+	if(x) {
+		if(x->tm_min < 10)
+			sprintf(s, "%d/%d/%d %d:0%d",x->tm_mday, x->tm_mon + 1, x->tm_year + 1900,
+				x->tm_hour, x->tm_min);
+		else
+			sprintf(s, "%d/%d/%d %d:%d",x->tm_mday, x->tm_mon + 1, x->tm_year + 1900,
+				x->tm_hour, x->tm_min);	
+	}
+#endif
+	return 1;
+}
+
+char* ConvertFullTime(time_t tt)
+{
+	char *days[7] = {
+		MESSAGEMAIN_DATETIME_DAY_SUN,
+		MESSAGEMAIN_DATETIME_DAY_MON,
+		MESSAGEMAIN_DATETIME_DAY_TEU,
+		MESSAGEMAIN_DATETIME_DAY_WED,
+		MESSAGEMAIN_DATETIME_DAY_THU,
+		MESSAGEMAIN_DATETIME_DAY_FRI,
+		MESSAGEMAIN_DATETIME_DAY_SAT
+	};
+	char *months[12] = {
+		MESSAGEMAIN_DATETIME_JAN,
+		MESSAGEMAIN_DATETIME_FEB,
+		MESSAGEMAIN_DATETIME_MAR,
+		MESSAGEMAIN_DATETIME_APR,
+		MESSAGEMAIN_DATETIME_MAY,
+		MESSAGEMAIN_DATETIME_JUN,
+		MESSAGEMAIN_DATETIME_JUL,
+		MESSAGEMAIN_DATETIME_AUG,
+		MESSAGEMAIN_DATETIME_SEP,
+		MESSAGEMAIN_DATETIME_OCT,
+		MESSAGEMAIN_DATETIME_NOV,
+		MESSAGEMAIN_DATETIME_DEC
+	};
+	static char s[1000];
+	tm *x;
+
+	x = localtime(&tt);
+	sprintf(s, "%s, %s %d %d:%02d:%02d %d", days[x->tm_wday], months[x->tm_mon], x->tm_mday, x->tm_hour, x->tm_min, x->tm_sec, x->tm_year + 1900);
+
+	return s;
+}
+
+void DB_Base::Profile_UserName(char *name, char *tostr, int reg, int doparsehtml)
+{
+	char *str, *str1;
+	if(reg) {
+		if(doparsehtml) str = FilterHTMLTags(name, AUTHOR_NAME_LENGTH*3+1, 0);
+		else str = name;
+		str1 = CodeHttpString(name, 0);	// do not allocate memory, use internal buffer
+		sprintf(tostr, "<A HREF=\"%s?uinfo=%s\" target=\"_blank\"><B>%s</B></A>", MY_CGI_URL, str1, str);
+	}
+	else
+		sprintf(tostr, DESIGN_MESSAGE_UNREG, name);
+}
+
+/* this function could not print more than 32000 messages at once */
+int DB_Base::printThreadbuffer(SMessage *buf, DWORD size, int p, DWORD fmpos, int ll,
+							  int *czero, DWORD selected, DWORD root, int *bp)
+{
+	if(p) {
+		DWORD count = size/sizeof(SMessage);
+		for(DWORD i = 0; i < count; i++) {
+			
+			if(fmpos + i*sizeof(SMessage) == root) (*bp) = 1;
+			if((*bp)){
+				if(invflag != -1 || ((buf[i].Flag & MESSAGE_IS_INVISIBLE) != 0))
+				{
+					if(((buf[i].Flag & MESSAGE_IS_INVISIBLE) != 0) && (invflag == -1))
+					{
+						invflag = buf[i].Level;
+					}
+					else
+					{	// (buf[i].Flag & MESSAGE_IS_INVISIBLE) == TRUE, invflag != -1
+						// seems that invisibility was already started
+						if(invflag >= buf[i].Level)
+						{
+							if((buf[i].Flag & MESSAGE_IS_INVISIBLE) == 0)
+							{
+								// invisible message ended
+								invflag = -1;
+								goto L_BVisible1;
+							}
+							else
+							{
+								// next message invisible too
+								invflag = buf[i].Level;
+							}
+						}
+					}
+					// if admin, show all
+					if((ULogin.LU.right & USERRIGHT_SUPERUSER) != 0) goto L_BVisible1;
+				}
+				else {
+L_BVisible1:
+					// we are printing content of a thread, READING THREAD
+					if(buf[i].Level != ll)
+					{
+						if(ll > buf[i].Level)
+						{
+							int x = ll - buf[i].Level;
+							for(int j = 0; j < x ; j++) printf(DESIGN_close_dl);
+							ll = buf[i].Level;
+						}
+						else
+						{
+							// only 1 level increase allowed
+							printf(DESIGN_open_dl);
+							ll = buf[i].Level;
+						}
+					}
+					else if (buf[i].Level > 0) {
+						// br before messages on one level, READING, 111!!
+						printf(DESIGN_break);
+					}
+
+					if(buf[i].Level == 0)
+					{
+						(*czero)++;
+						if(*czero == 2)
+						{
+							return ll;
+						}
+					}
+				
+					if(selected != buf[i].ViIndex)
+					{
+						printhtmlmessage_in_index(&buf[i], MESSAGE_INDEX_PRINT_ITS_URL | MESSAGE_INDEX_DISABLE_ROLLED);
+					}
+					else
+					{
+						printhtmlmessage_in_index(&buf[i], MESSAGE_INDEX_DISABLE_ROLLED);
+					}
+				}
+			}
+		}
+	}
+	else {
+		DWORD count = size/sizeof(SMessage) - 1;
+		for(signed long i = count; i >= 0; i--)
+		{
+			
+			if(fmpos + i*sizeof(SMessage) == root) (*bp) = 1;
+			if(*bp)
+			{
+				if(invflag != -1 || ((buf[i].Flag & MESSAGE_IS_INVISIBLE) != 0))
+				{
+					if(((buf[i].Flag & MESSAGE_IS_INVISIBLE) != 0) && (invflag == -1))
+					{
+						invflag = buf[i].Level;
+					}
+					else
+					{
+						if(invflag >= buf[i].Level)
+						{
+							if((buf[i].Flag & MESSAGE_IS_INVISIBLE) == 0)
+							{
+								// invisible message ended
+								invflag = -1;
+								goto L_BVisible2;
+							}
+							else
+							{
+								// next message invisible too
+								invflag = buf[i].Level;
+							}
+						}
+					}
+					// if superuser, show all
+					if(ULogin.LU.right & USERRIGHT_SUPERUSER) goto L_BVisible2;
+				}
+				else
+				{
+L_BVisible2:
+					if(buf[i].Level != ll)
+					{
+						if(ll > buf[i].Level)
+						{
+							int x = ll - buf[i].Level;
+							for(int j = 0; j < x ; j++) printf(DESIGN_close_dl);
+							ll = buf[i].Level;
+						}
+						else
+						{
+							// only 1 level increase allowed
+							printf(DESIGN_open_dl);
+							ll = buf[i].Level;
+						}
+					}
+					else if (buf[i].Level > 0) {
+						// br before messages on one level, READING, 111!!
+						printf(DESIGN_break);
+					}
+
+					if(buf[i].Level == 0)
+					{
+						(*czero)++;
+						if(*czero == 2)
+						{
+							return ll;
+						}
+					}
+					if(selected != buf[i].ViIndex)
+					{
+						printhtmlmessage_in_index(&buf[i], MESSAGE_INDEX_PRINT_ITS_URL | MESSAGE_INDEX_DISABLE_ROLLED);
+					}
+					else
+					{
+						printhtmlmessage_in_index(&buf[i], MESSAGE_INDEX_DISABLE_ROLLED);
+					}
+				}
+			}
+		}
+	}
+	return ll;
+}
+
+/* this function could not print more than 32000 messages at once */
+int DB_Base::printhtmlbuffer(SMessage *buf, DWORD size, int p/*direction*/, int *ll, int *pr, DWORD mode, DWORD &shouldprint, DWORD &skipped)
+{
+	
+	if(p)
+	{
+		DWORD count = size/sizeof(SMessage);
+		for(DWORD i = 0; i < count; i++)
+		{
+#if TOPICS_SYSTEM_SUPPORT
+			// check for topic match our topic mask
+			if(buf[i].Level == 0) {
+				// check should we stop printing because of data limitation
+				if(buf[i].Date < current_minprntime && currentlsel == 1) {
+					return 0;
+				}
+				if( !((1 << buf[i].Topics) & currenttopics) )
+				{
+					invflag = 0;
+					collapsed = 1;
+					skipped |= 0xf0000000;
+					continue;
+				}
+			}
+#endif
+			// check for view mode == all rolled
+			if((mode & PRINTMODE_ALL_ROLLED) && buf[i].Level == 0) {
+				invflag = buf[i].Level;
+				collapsed = 1;
+				/* show first message of the thread */
+				goto L_BVisible1;
+			}
+
+			if(invflag != -1 || (buf[i].Flag & MESSAGE_IS_INVISIBLE) ||
+				(buf[i].Flag & MESSAGE_COLLAPSED_THREAD))
+			{
+				
+				if((invflag == -1) && ((buf[i].Flag & MESSAGE_IS_INVISIBLE) ||
+					(buf[i].Flag & MESSAGE_COLLAPSED_THREAD)))
+				{
+					//
+					//	Starting invsible/rolled message check
+					//
+					invflag = buf[i].Level;
+					if(buf[i].Flag & MESSAGE_COLLAPSED_THREAD)
+					{
+						collapsed = 1;
+						// can we show it ?
+						if((buf[i].Flag & MESSAGE_IS_INVISIBLE) != 0) {
+							if((ULogin.LU.right & USERRIGHT_SUPERUSER) != 0) {
+								/* show first message of the rolled thread */
+								goto L_BVisible1;
+							}
+						}
+						else goto L_BVisible1;
+					}
+				}
+				else
+				{
+					//
+					//	Check for stopping rolled/invisible thread
+					//
+					if(invflag >= buf[i].Level)
+					{
+						if(buf[i].Flag & MESSAGE_IS_INVISIBLE)
+						{
+							/* next message invisible too */
+							invflag = buf[i].Level;
+
+							if((ULogin.LU.right & USERRIGHT_SUPERUSER)) {
+								if((buf[i].Flag & MESSAGE_COLLAPSED_THREAD) != 0) {
+									collapsed = 1;
+									goto L_BVisible1;
+								}
+								else collapsed = 0;
+							}
+						}
+						else
+						{
+							/* invisible or collapsed message ended or not ?*/
+							if((buf[i].Flag & MESSAGE_COLLAPSED_THREAD) == 0 && collapsed) {
+								/* next message collapsed too */
+								invflag = -1;
+								collapsed = 0;
+							}
+							else if(collapsed == 0 && (buf[i].Flag & MESSAGE_COLLAPSED_THREAD) != 0) {
+								collapsed = 1;
+							}
+							else if(collapsed == 1 && (buf[i].Flag & MESSAGE_COLLAPSED_THREAD) != 0) {
+							}
+							else {
+							    invflag = -1;
+							}
+							goto L_BVisible1;
+						}
+					}
+				}
+
+				/* if admin, show all invisible messages */
+				if((ULogin.LU.right & USERRIGHT_SUPERUSER)  && (!collapsed))
+					goto L_BVisible1;
+#if ALLOW_MARK_NEW_MESSAGES
+				/* check for new message mark */
+				if((collapsed) && currentlm < buf[i].ViIndex && (skipped & 0xf0000000) == 0) {
+					if(newmessflag) {
+						if(lastmes.Date < buf[i].Date)
+							memcpy(&lastmes, &(buf[i]), sizeof(SMessage));
+					}
+					else memcpy(&lastmes, &(buf[i]), sizeof(SMessage));
+					newmessflag++;
+				}
+#endif
+				if(buf[i].Level == 0) skipped |= 0xf0000000;
+				if((skipped & 0xf0000000) == 0) skipped++;
+			}
+			else {
+L_BVisible1:
+				/* check if it's end of thread and if it is increase already printed count
+				* also check should we stop printing
+				*/
+				
+				if(currentlm < buf[i].ViIndex){
+					nm_counter ++;
+					if(buf[i].Level == 0)
+						nt_counter ++; 
+				}
+				
+				if(buf[i].Level == 0)
+				{
+					alrprn++;
+					// check should we stop printing
+					if( (currentlsel == 1 && buf[i].Date < current_minprntime) ||
+						(currentlsel == 2 && alrprn == currenttc + 1) )
+					{
+						return 0;
+					}
+				}
+
+				int delayprint = 0;
+				if(shouldprint != 0xFFFFFFFF) {
+					// full collapsed thread, INDEX
+					//printf("<BR>33");
+
+					skipped &= (~0xf0000000);
+					// delayed print done
+					if(skipped) delayprint = 1;
+					printhtmlmessage_in_index(&pmes, MESSAGE_INDEX_PRINT_ITS_URL, skipped, newmessflag);
+					newmessflag = 0;
+					shouldprint = 0xFFFFFFFF;
+					skipped = 0;
+				}
+
+				// there more than 1 message in thread, MAIN INDEX!
+				if(buf[i].Level != (*ll)) {
+					if((*ll) > buf[i].Level) {
+						int x = (*ll) - buf[i].Level;
+						for(int j = 0; j < x ; j++) printf(DESIGN_close_dl);
+						(*ll) = buf[i].Level;
+					}
+					else {
+						// only 1 level of message increase allowed
+						printf(DESIGN_open_dl);
+						(*ll) = buf[i].Level;
+					}
+				}
+				else if (buf[i].Level > 0){
+					// br before messages on one level, INDEX, 44!!
+					if(!delayprint) printf(DESIGN_break);
+				}
+			
+				if(buf[i].Level == 0 && (*pr)) {
+					// div's alternating color
+					printf("%s%s",DESIGN_close_dl, DESIGN_threads_divider);
+					if(curcolor) printf(DESIGN_open_dl_white);
+					else printf(DESIGN_open_dl_grey);
+					curcolor = !curcolor;
+				}
+				else (*pr) = 1;
+
+				if(!collapsed) {
+					//printf("<BR>44");
+
+					printhtmlmessage_in_index(&buf[i], MESSAGE_INDEX_PRINT_ITS_URL);
+				}
+				else {
+					shouldprint = i;
+					skipped = 0;
+					newmessflag = 0;
+					memcpy(&pmes, &buf[i], sizeof(SMessage));
+				}
+			}
+		}
+	}
+	else {
+		DWORD count = size/sizeof(SMessage) - 1;
+		for(signed long i = count; i >= 0; i--)
+		{
+#if TOPICS_SYSTEM_SUPPORT
+			// check for topic match our topic mask
+			if(buf[i].Level == 0) {
+				// check should we stop printing because of data limitation
+				if(buf[i].Date < current_minprntime && currentlsel == 1) {
+					return 0;
+				}
+				if( !((1 << buf[i].Topics) & currenttopics) )
+				{
+					invflag = 0;
+					collapsed = 1;
+					skipped |= 0xf0000000;
+					continue;
+				}
+			}
+#endif
+
+			// check for view mode == all rolled
+			if((mode & PRINTMODE_ALL_ROLLED) && buf[i].Level == 0) {
+				invflag = buf[i].Level;
+				collapsed = 1;
+				/* show first message of the thread */
+				goto L_BVisible2;
+			}
+
+			if(invflag != -1 || (buf[i].Flag & MESSAGE_IS_INVISIBLE) ||
+				(buf[i].Flag & MESSAGE_COLLAPSED_THREAD))
+			{
+				
+				if((invflag == -1) && ((buf[i].Flag & MESSAGE_IS_INVISIBLE) ||
+					(buf[i].Flag & MESSAGE_COLLAPSED_THREAD)))
+				{
+					//
+					//	Starting invsible/rolled message check
+					//
+					invflag = buf[i].Level;
+					if(buf[i].Flag & MESSAGE_COLLAPSED_THREAD)
+					{
+						collapsed = 1;
+						// can we show it ?
+						if((buf[i].Flag & MESSAGE_IS_INVISIBLE) != 0) {
+							if((ULogin.LU.right & USERRIGHT_SUPERUSER) != 0) {
+								/* show first message of the rolled thread */
+								goto L_BVisible2;
+							}
+						}
+						else goto L_BVisible2;
+					}
+				}
+				else
+				{
+					//
+					//	Check for stopping rolled/invsible thread
+					//
+					if(invflag >= buf[i].Level)
+					{
+						if(buf[i].Flag & MESSAGE_IS_INVISIBLE)
+						{
+							/* next message invisible too */
+							invflag = buf[i].Level;
+
+							if((ULogin.LU.right & USERRIGHT_SUPERUSER)) {
+								if((buf[i].Flag & MESSAGE_COLLAPSED_THREAD) != 0) {
+									collapsed = 1;
+									goto L_BVisible2;
+								}
+								else collapsed = 0;
+							}
+						}
+						else
+						{
+							/* invisible or collapsed message ended or not ?*/
+							if((buf[i].Flag & MESSAGE_COLLAPSED_THREAD) == 0 && collapsed) {
+								/* next message collapsed too */
+								invflag = -1;
+								collapsed = 0;
+							}
+							else if(collapsed == 0 && (buf[i].Flag & MESSAGE_COLLAPSED_THREAD) != 0) {
+								collapsed = 1;
+							}
+							else if(collapsed == 1 && (buf[i].Flag & MESSAGE_COLLAPSED_THREAD) != 0) {
+							}
+							else {
+							    invflag = -1;
+							}
+							goto L_BVisible2;
+						}
+					}
+				}
+				/* if admin, show all invisible messages */
+				if((ULogin.LU.right & USERRIGHT_SUPERUSER) && (!collapsed))
+					goto L_BVisible2;
+#if ALLOW_MARK_NEW_MESSAGES
+				/* check for new message mark */
+				if((collapsed) && currentlm < buf[i].ViIndex && (skipped & 0xf0000000) == 0) {
+					if(newmessflag) {
+						if(lastmes.Date < buf[i].Date)
+							memcpy(&lastmes, &(buf[i]), sizeof(SMessage));
+					}
+					else memcpy(&lastmes, &(buf[i]), sizeof(SMessage));
+					newmessflag++;
+				}
+#endif
+				if(buf[i].Level == 0) skipped |= 0xf0000000;
+				if((skipped & 0xf0000000) == 0) skipped++;
+			}
+			else
+			{
+L_BVisible2:
+				/* check if it's end of thread and if it is increase already printed count
+				* also check should we stop printing 
+				*/
+				
+				if(currentlm < buf[i].ViIndex){
+					nm_counter ++;
+					if(buf[i].Level == 0)
+						nt_counter ++; 
+				}
+				
+				if(buf[i].Level == 0)
+				{
+					alrprn++;
+					// check should we stop printing
+					if( (currentlsel == 1 && buf[i].Date < current_minprntime) ||
+						(currentlsel == 2 && alrprn == currenttc + 1) )
+					{
+						return 0;
+					}
+				}
+
+				int delayprint = 0;
+				if(shouldprint != 0xFFFFFFFF) {
+					// before collapsed sub thread in main INDEX
+
+					skipped &= (~0xf0000000);
+					// delayed print done
+					if(skipped) delayprint = 1;
+					printhtmlmessage_in_index(&pmes, MESSAGE_INDEX_PRINT_ITS_URL, skipped, newmessflag);
+					newmessflag = 0;
+					shouldprint = 0xFFFFFFFF;
+					skipped = 0;
+				}
+
+				// only one message in (sub) thread, could be collapsed, MAIN INDEX
+				if(buf[i].Level != (*ll))
+				{
+					if((*ll) > buf[i].Level)
+					{
+						int x = (*ll) - buf[i].Level;
+						for(int j = 0; j < x ; j++) printf(DESIGN_close_dl);
+						(*ll) = buf[i].Level;
+					}
+					else
+					{
+						/* only 1 level increase allowed */
+						printf(DESIGN_open_dl);
+						(*ll) = buf[i].Level;
+					}
+				}
+				else if (buf[i].Level > 0){
+					// br before messages on one level, INDEX, 44!!
+					if(!delayprint) printf(DESIGN_break);
+				}
+
+				if(buf[i].Level == 0 && (*pr)) {
+					// div's alternating color
+					printf("%s%s", DESIGN_close_dl, DESIGN_threads_divider);
+					if(curcolor) printf(DESIGN_open_dl_white);
+					else printf(DESIGN_open_dl_grey);
+					curcolor = !curcolor;
+				}
+				else (*pr) = 1;
+
+				if(!collapsed) {
+					//printf("<BR>66");
+
+					printhtmlmessage_in_index(&buf[i], MESSAGE_INDEX_PRINT_ITS_URL);
+				}
+				else {
+					shouldprint = i;
+					skipped = 0;
+					newmessflag = 0;
+					memcpy(&pmes, &buf[i], sizeof(SMessage));
+				}
+			}
+		}
+	}
+	return 1;
+}
+
+int DB_Base::DB_PrintHtmlIndex(time_t time1, time_t time2, DWORD mtc)
+{
+	curcolor = (mtc % 2);
+
+	//	if we have NULL topics - stop printing
+	if(currenttopics == 0) return 0;
+
+	switch(currentss) {
+	case 1:
+		return printhtmlindexhron_bythreads(PRINTMODE_NULL);
+	case 2:
+		return printhtmlindexhron_bythreads(PRINTMODE_NULL);
+	case 3:
+		return printhtmlindexhron_wothreads();
+	case 4:
+		return printhtmlindexhron_bythreads(PRINTMODE_ALL_ROLLED);
+	}
+	return 1;
+}
+
+int DB_Base::printhtmlmessage_in_index(SMessage *mes, int style, DWORD skipped, int newmessmark)
+{
+	// define common used code printing afrer message header ([url],[pic], etc.)
+#define PRINT_COMMON_POST_MESSAGE_INFO() {\
+	if((mes->Flag & MESSAGE_HAVE_URL) == MESSAGE_HAVE_URL)\
+		printf(TAG_MSG_HAVE_URL);\
+	if((mes->Flag & MESSAGE_HAVE_BODY) != MESSAGE_HAVE_BODY)\
+		printf(TAG_MSG_HAVE_NO_BODY);\
+	if((mes->Flag & MESSAGE_HAVE_PICTURE) == MESSAGE_HAVE_PICTURE)\
+		printf(TAG_MSG_HAVE_PIC);\
+}
+
+	// define common used code printing before message header (topic)
+#define PRINT_COMMON_PREV_MESSAGE_INFO() {\
+	if(mes->Topics <= TOPICS_COUNT - 1 && mes->Level == 0 && mes->Topics  != 0) {\
+		printf(DESIGN_TOPIC_TAG_OPEN "%s" DESIGN_TOPIC_TAG_CLOSE DESIGN_TOPIC_DIVIDER,Topics_List[mes->Topics]);\
+	}\
+}
+	// *******************************
+	// BUG BUG with aname
+	//////////////////////////////////
+	char *mp = NULL, aname[1000], tm[200];
+	DWORD ff;
+	DWORD flg;
+	
+	/*if(strcmp(mes->HostName, "172.16.1.130") == 0)
+	    return 0;*/
+
+#if ALLOW_MARK_NEW_MESSAGES == 2
+	if((currentdsm & 16) != 0) {
+		if(currentlm < mes->ViIndex || newmessmark) printf(TAG_NEW_MSG_MARK_HREF,newhref,++newhref+1);
+	}
+	else {
+		if(currentlm < mes->ViIndex || newmessmark) printf(TAG_NEW_MSG_MARK);
+	}
+#endif
+#if ALLOW_MARK_NEW_MESSAGES == 1
+	if(currentlm < mes->ViIndex || newmessmark) printf(TAG_NEW_MSG_MARK);
+#endif
+
+	ConvertTime(mes->Date, tm);
+
+	// check whether smiles have been disabled globally
+	if((currentdsm & 1) == 0) flg = MESSAGE_ENABLED_TAGS | MESSAGE_ENABLED_SMILES;
+	else flg = MESSAGE_ENABLED_TAGS;
+	if(FilterBoardTags(mes->MessageHeader, &mp, mes->SecHeader, MAX_PARAMETERS_STRING,
+		flg, &ff) != 0) {
+	}
+	else mp = (char*)(&mes->MessageHeader);
+
+	// does this message posted by registred user ?
+	if(mes->UniqUserID == 0) sprintf(aname, DESIGN_UNREGISTRED_NICK, mes->AuthorName);
+	else {
+		char altnick[1000];
+
+		if((currentdsm & 0x40) == 0) {
+			//
+			//	first of all translate to to alt nick if requred
+			//
+			if(!AltNames.NameToAltName(mes->UniqUserID, altnick)) {
+				strcpy(altnick, mes->AuthorName);
+			}
+		}
+		else strcpy(altnick, mes->AuthorName);
+
+		// if this, is does this user view this message ;-) ?
+		if( ((currentdsm & 0x08) == 0) && ULogin.LU.ID[0] !=0 && mes->UniqUserID == ULogin.LU.UniqID ) {
+			sprintf(aname, DESIGN_REGISTRED_OWN_NICK, altnick);
+		}
+		else {
+			char *ts;
+			// maybe user has selected some nicks to be displayed as detailed nicks?
+			if(ULogin.LU.ID[0] != 0 && ((ts = strstr(ULogin.pfui->SelectedUsers, mes->AuthorName)) != NULL)) {
+				sprintf(aname, DESIGN_SELECTEDUSER_NICK, altnick);
+			}
+			else {
+				sprintf(aname, DESIGN_REGISTRED_NICK, altnick);
+			}
+		}
+	}
+
+	if(mes->Flag & MESSAGE_IS_CLOSED) printf(TAG_MSG_CLOSED_THREAD);
+/*	if((mes->Flag & MESSAGE_COLLAPSED_THREAD) && ((style & MESSAGE_INDEX_DISABLE_ROLLED) == 0))
+			printf(TAG_MSG_ROLLED_THREAD);*/
+
+	if((mes->Flag & MESSAGE_IS_INVISIBLE) != 0) 
+		printf("<SMALL>");
+
+	printf("<A NAME=%ld", mes->ViIndex);
+	if(MESSAGE_INDEX_PRINT_ITS_URL & style)
+		printf(" HREF=\"%s?read=%ld\"",MY_CGI_URL, mes->ViIndex);
+	if(MESSAGE_INDEX_PRINT_BLANK_URL & style)
+		printf(" TARGET=\"_blank\"");
+	if((MESSAGE_INDEX_PRINT_ITS_URL & style) == 0) printf("><B>");
+	else printf(">");
+#if	TOPICS_SYSTEM_SUPPORT
+	PRINT_COMMON_PREV_MESSAGE_INFO();
+#endif
+	// subject
+	printf("%s", mp);
+	if((MESSAGE_INDEX_PRINT_ITS_URL & style) == 0) printf("</B>");
+		
+	PRINT_COMMON_POST_MESSAGE_INFO();
+
+	if(mes->Readed) printf("</A> <EM>(%d)</EM>", mes->Readed);
+	else printf("</A>");
+
+	printf(" -- <nobr>%s</nobr>", aname);
+	if((currentdsm & 32) == 0)printf(" <EM>(%s)</EM>", mes->HostName);
+	printf(" -- <EM>%s</EM>", tm);
+
+	if((mes->Flag & MESSAGE_IS_INVISIBLE) != 0) 
+		printf("</SMALL>");
+
+	if(skipped != 0xffffffff && skipped != 0) {
+		if(newmessmark) {
+			// does this message posted by registred user ?
+			if(lastmes.UniqUserID == 0) sprintf(aname, DESIGN_UNREGISTRED_NICK, lastmes.AuthorName);
+			else {
+				char altnick[1000];
+
+				if((currentdsm & 0x40) == 0) {
+					//
+					//	first of all translate to to alt nick if requred
+					//
+					if(!AltNames.NameToAltName(lastmes.UniqUserID, altnick)) {
+						strcpy(altnick, lastmes.AuthorName);
+					}
+				}
+				else strcpy(altnick, lastmes.AuthorName);
+
+				// if this, is does this user view this message ;-) ?
+				if( ((currentdsm & 0x08) == 0) && ULogin.LU.ID[0] !=0 && lastmes.UniqUserID == ULogin.LU.UniqID ) {
+					sprintf(aname, DESIGN_REGISTRED_OWN_NICK, altnick);
+				}
+				else {
+					char *ts;
+					// maybe user has selected some nicks to be displayed as detailed nicks?
+					if(ULogin.LU.ID[0] != 0 && ((ts = strstr(ULogin.pfui->SelectedUsers, lastmes.AuthorName)) != NULL)) {
+						sprintf(aname, DESIGN_SELECTEDUSER_NICK, altnick);
+					}
+					else {
+						sprintf(aname, DESIGN_REGISTRED_NICK, altnick);
+					}
+				}
+			}
+			ConvertTime(lastmes.Date, tm);
+			printf(TAG_ONLYHEADERS_POSTCNT_MARKNEW, DESIGN_open_dl, TAG_MSG_ROLLED_THREAD,
+				skipped, newmessmark, MY_CGI_URL, lastmes.ViIndex, aname,
+				tm, DESIGN_close_dl);
+		}
+		else
+			printf(TAG_ONLYHEADERS_POSTCNT, DESIGN_open_dl, TAG_MSG_ROLLED_THREAD,
+				skipped, DESIGN_close_dl);
+	}
+
+	if(mp != (char*)&mes->MessageHeader) free(mp);
+	return 1;
+}
+
+int DB_Base::PrintHtmlMessageBufferByVI(DWORD *VI, DWORD cnt)
+{
+	SMessage msgs;
+	DWORD fmpos, i;
+	WCFILE *m;
+	
+	/* initializing */
+	alrprn = 0;
+
+	invflag = -1;
+	collapsed = 0;
+	newmessflag = 0;
+
+	if((m = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+
+	// search result entry
+	printf(DESIGN_open_dl);
+
+	for(i = 0; i < cnt; i++) {
+
+		fmpos = TranslateMsgIndex(VI[i]);
+
+		if(fmpos == NO_MESSAGE_CODE)
+			continue;
+
+		if(wcfseek(m, fmpos, SEEK_SET) < 0) {
+			wcfclose(m);
+			return 0;
+		}
+
+		if(!fCheckedRead(&msgs, sizeof(SMessage), m))
+			printhtmlerror();
+
+		// check if user have superuser permissions if message is invisible
+		if( ((msgs.Flag & MESSAGE_IS_INVISIBLE) == 0) ||
+		    ((msgs.Flag & MESSAGE_IS_INVISIBLE) != 0 && (ULogin.LU.right & USERRIGHT_SUPERUSER) != 0) ) {
+		    printf(DESIGN_break);
+		    printhtmlmessage_in_index(&msgs, MESSAGE_INDEX_PRINT_ITS_URL | MESSAGE_INDEX_PRINT_BLANK_URL | MESSAGE_INDEX_DISABLE_ROLLED);
+		}
+	}
+	printf(DESIGN_close_dl);
+	wcfclose(m);
+	return 1;
+}
+
+int DB_Base::PrintandCheckMessageFavsExistandInv(SProfile_UserInfo *ui, DWORD viewinv, int *updated)
+{
+
+	SMessage msgs;
+	DWORD fmpos, cnt = 0;
+	int i;
+	WCFILE *m;
+	*updated = 0;
+
+	printf(DESIGN_open_dl);
+	printf("<P>");
+	/* initializing */
+	if((m = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+	// search result entry
+	for(i = PROFILES_FAV_THREADS_COUNT - 1; i + 1 > 0; i--) {
+		
+		if((fmpos = TranslateMsgIndex(ui->favs[i])) == NO_MESSAGE_CODE){
+			ui->favs[i] = 0;
+			*updated = 1;
+			continue;
+		}
+		if(wcfseek(m, fmpos, SEEK_SET) < 0) {
+			wcfclose(m);
+			return 0;
+		}
+
+		if(!fCheckedRead(&msgs, sizeof(SMessage), m)) printhtmlerror();
+		if((msgs.Flag & MESSAGE_IS_INVISIBLE) && viewinv == 0) {
+			ui->favs[i] = 0;
+			*updated = 1;
+			continue;
+		}
+		printf(DESIGN_break);
+		cnt++;
+		printf("%ld." "<A HREF=" MY_CGI_URL "?favdel=%ld target=_blank>" DESIGN_FAVORITES_DEL_THREAD "</A> ",
+			cnt, ui->favs[i]);
+		printhtmlmessage_in_index(&msgs, MESSAGE_INDEX_PRINT_ITS_URL | MESSAGE_INDEX_PRINT_BLANK_URL | MESSAGE_INDEX_DISABLE_ROLLED);
+	}
+	wcfclose(m);
+	printf(DESIGN_close_dl);
+	printf("<P>");
+	return cnt;
+}
+
+int DB_Base::printhtmlindexhron_wothreads()
+{
+	SMessage msgs;
+	DWORD fpos, fmpos;
+	WCFILE *f, *m;
+	
+	// initializing
+	alrprn = 0;
+	invflag = -1;
+	collapsed = 0;
+	newmessflag = 0;
+	
+	if((f = wcfopen(F_VINDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+	if((m = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+
+	printf(DESIGN_open_dl);
+	
+	if(wcfseek(f, 0, SEEK_END) != 0) printhtmlerror();
+	fpos = wcftell(f);
+
+	do {
+		if(fpos == 4) break;
+		
+		fpos-=sizeof(DWORD);
+
+		if(wcfseek(f, fpos, SEEK_SET) < 0) printhtmlerror();
+		if(!fCheckedRead(&fmpos, sizeof(DWORD), f))
+			printhtmlerror();
+
+		if(fmpos == NO_MESSAGE_CODE) continue;
+
+		printf(DESIGN_break);
+
+		if(wcfseek(m, fmpos, SEEK_SET) != 0)
+			printhtmlerror();
+		if(!fCheckedRead(&msgs, sizeof(SMessage), m))
+			printhtmlerror();
+
+		printhtmlmessage_in_index(&msgs, MESSAGE_INDEX_PRINT_ITS_URL | MESSAGE_INDEX_DISABLE_ROLLED);
+
+		alrprn++;
+
+	} while((currentlsel == 1 && msgs.Date > current_minprntime) ||
+		(currentlsel == 2 && alrprn != currenttc + 1));
+
+	printf(DESIGN_close_dl);
+
+	wcfclose(f);
+	wcfclose(m);
+
+	return 1;
+}
+
+int DB_Base::printhtmlindexhron_bythreads(DWORD mode)
+{
+	SMessageTable *buf;
+	SMessage *msgs;
+	DWORD rr, fmpos, shouldprint = 0xFFFFFFFF, skipped = 0;
+	DWORD fipos;
+	int LastLevel = 0;
+	int firprn = 0;
+	
+	// initializing
+	alrprn = 0;
+	invflag = -1;
+	collapsed = 0;
+	newmessflag = 0;
+	nt_counter = 0;
+	nm_counter = 0;
+	
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_R)) == NULL)
+		printhtmlerrorat(LOG_UNABLETOLOCATEFILE, F_MSGINDEX);
+	if((fi = wcfopen(F_INDEX, FILE_ACCESS_MODES_R)) == NULL)
+		printhtmlerrorat(LOG_UNABLETOLOCATEFILE, F_INDEX);
+
+	if(wcfseek(fi, 0, SEEK_END) != 0) printhtmlerror();
+	
+	buf = (SMessageTable *)malloc(sizeof(SMessageTable)*READ_MESSAGE_TABLE + 1);
+	msgs = (SMessage *)malloc(sizeof(SMessage)*READ_MESSAGE_HEADER + 1);
+
+	fipos = wcftell(fi);
+
+	// beginning thread envelope - div
+	if (curcolor) printf(DESIGN_open_dl_white);
+	else printf(DESIGN_open_dl_grey);
+	curcolor=!curcolor;
+
+	for(;;) {
+		DWORD tord;
+		if(fipos == 0) break;
+		else {
+			if(fipos >= READ_MESSAGE_TABLE*sizeof(SMessageTable)) {
+				fipos = fipos - READ_MESSAGE_TABLE*sizeof(SMessageTable);
+				tord = READ_MESSAGE_TABLE*sizeof(SMessageTable);
+			}
+			else {
+				tord = fipos;
+				fipos = 0;
+			}
+		}
+		
+		if(wcfseek(fi, fipos, SEEK_SET) != 0) printhtmlerror();
+		if((rr = wcfread(buf, 1, tord, fi))  != tord) printhtmlerror();
+		
+		signed long i = rr / sizeof(SMessageTable) - 1;
+		
+		while(i >= 0) {
+			if(buf[i].begin < buf[i].end ) {
+				// forward direction
+				fmpos = buf[i].begin;
+				if(wcfseek(fm, fmpos, SEEK_SET) == -1) printhtmlerror();
+				while(fmpos != (buf[i].end + 1)) {
+					DWORD toread;
+					if(buf[i].end - fmpos < READ_MESSAGE_HEADER*sizeof(SMessage)) {
+						toread = buf[i].end - fmpos + 1;
+						fmpos = fmpos + toread;
+					}
+					else {
+						toread = READ_MESSAGE_HEADER*sizeof(SMessage);
+						fmpos = fmpos + toread;
+					}
+					if(!fCheckedRead(msgs, toread, fm)) printhtmlerror();
+					
+					if(printhtmlbuffer(msgs, toread, PRINT_FORWARD, &LastLevel, &firprn, mode, shouldprint, skipped) == 0) {
+						goto End_of_Prn;
+					}
+					
+				}
+			}
+			else {
+				// backward direction
+				DWORD toread;
+				fmpos = buf[i].begin + 1;
+				while(fmpos != buf[i].end) {
+					if( fmpos - buf[i].end > READ_MESSAGE_HEADER*sizeof(SMessage)) {
+						fmpos = fmpos - READ_MESSAGE_HEADER*sizeof(SMessage);
+						toread = READ_MESSAGE_HEADER*sizeof(SMessage);
+					}
+					else {
+						toread = fmpos - buf[i].end;
+						fmpos = buf[i].end;
+					}
+					
+					if(wcfseek(fm, fmpos, SEEK_SET) == -1) printhtmlerror();
+					if(!fCheckedRead(msgs, toread, fm)) printhtmlerror();
+					
+					if(printhtmlbuffer(msgs, toread, PRINT_BACKWARD, &LastLevel, &firprn, mode, shouldprint, skipped) == 0) {
+						goto End_of_Prn;
+					}
+				}
+			}
+			i--;
+		}
+	}
+End_of_Prn:
+	
+	for(int i = -1; i < LastLevel; i++) printf(DESIGN_close_dl);
+	
+	DWORD totalcount = MessageCountInDB();
+	printf(MESSAGEMAIN_WELCOME_NEWCOUNT_SCRIPT);
+	if(nm_counter)
+		printf(MESSAGEMAIN_WELCOME_NEWCOUNT_SCRIPT_NEW, nt_counter, nm_counter, totalcount);
+	else printf(MESSAGEMAIN_WELCOME_NEWCOUNT_SCRIPT_NO_NEW, totalcount);
+
+	free(buf);
+	free(msgs);
+	wcfclose(fi);
+	wcfclose(fm);
+	return 1;	
+}
+
+DB_Base::DB_Base()
+{
+	fi = NULL;
+	fb = NULL;
+	fm = NULL;
+	fv = NULL;
+}
+
+DB_Base::~DB_Base()
+{
+	
+}
+
+/* insert message "mes" with body "body" acording CFlags to board
+ * REMARKS: mes->Host should be IP address, not a DNS name,
+ * this function DOESN'T SET CURRENT DATE AND TIME
+ * returns 0 if successfull, otherwise error code returned
+ */
+int DB_Base::DB_InsertMessage(struct SMessage *mes, DWORD root, WORD msize, char** body,
+							  DWORD CFlags, char *passw, char **banreason)
+{
+	DWORD fp,fl;
+	DWORD ri,fisize, rd;
+	SMessageTable *buf;
+	SMessage *msg;
+	unsigned char haddr[4];
+	void *tmp;
+	signed long i;
+	int code;
+	int re; // reply flag
+	hostent *he;
+	DWORD MFlags, msigned = 0;
+
+	CProfiles *uprof = NULL;
+	/* posting user SProfile_UserInfo absoulte index in profile database */
+	DWORD Uind = 0xFFFFFFFF;
+
+	/****** check User ******/
+	SProfile_UserInfo UI;
+	SProfile_FullUserInfo FUI;
+
+	if(passw != NULL && *passw != 0) {
+		uprof = new CProfiles();
+		if(uprof->errnum != PROFILE_RETURN_ALLOK) {
+#if ENABLE_LOG >= 1
+			print2log("Error working with profiles database (init)");
+#endif
+			printhtmlerror();
+		}
+		int opres = uprof->GetUserByName(mes->AuthorName, &UI, NULL, &Uind);
+		if((opres != PROFILE_RETURN_ALLOK) || (strcmp(UI.password, passw) != 0)) {
+			delete uprof;
+			return MSG_CHK_ERROR_INVALID_PASSW;
+		}
+	}
+	else {
+		if(ULogin.LU.ID[0] != 0) {
+			//
+			//	User was already logged in
+			//
+			memcpy(&UI, ULogin.pui, sizeof(UI));
+			strcpy(mes->AuthorName, UI.username);
+			Uind = ULogin.LU.SIndex;
+		}
+		else {
+			char *st;
+
+			/* default user */
+			UI.secur = DEFAULT_NOBODY_SECURITY_BYTE;
+			UI.secheader = DEFAULT_NOBODY_HDR_SEC_BYTE;
+			UI.right = DEFAULT_NOBODY_RIGHT;
+			UI.UniqID = 0;
+
+			//	check user name length ;-)
+			if(FilterBoardTags(mes->AuthorName, &st, 255, AUTHOR_NAME_LENGTH - 1, BOARDTAGS_TAG_PREPARSE, &fp) == 0) {
+				return MSG_CHK_ERROR_NONAME;
+			}
+			else {
+				strcpy(mes->AuthorName, st);
+				free(st);
+			}
+			if(strlen(mes->AuthorName) == 0 || strcmp(mes->AuthorName, " ") == 0) return MSG_CHK_ERROR_NONAME;
+#if POST_ALLOW_UNDER_SAME_NICK == 0
+			uprof = new CProfiles();
+			if(uprof->GetUserByName(mes->AuthorName, NULL, NULL, NULL) == PROFILE_RETURN_ALLOK) {
+				delete uprof;
+			    return MSG_CHK_ERROR_INVALID_PASSW;
+			}
+#endif
+		}
+	}
+
+
+
+// Check security rights for logged users
+		if( 
+			!(UI.right & USERRIGHT_SUPERUSER) && 
+			!((UI.right & USERRIGHT_CREATE_MESSAGE) && root) &&
+			!((UI.right & USERRIGHT_CREATE_MESSAGE_THREAD) && root == 0)) {
+			return MSG_CHK_ERROR_BANNED;
+		}
+												
+	if(UI.Flags & PROFILES_FLAG_HAVE_SIGNATURE) {
+		// set "signed" flag in message
+		msigned = 1;
+	}
+
+
+	//
+	//	Message security == user security !!!
+	//
+	if(UI.right & USERRIGTH_ALLOW_HTML) CFlags = CFlags | MSG_CHK_ALLOW_HTML;
+	mes->Security = UI.secur;
+	mes->SecHeader = UI.secheader;
+	// set poster ID of message
+	mes->UniqUserID = UI.UniqID;
+
+	// message header, banned address and spelling message check
+	switch (code = CheckSpellingBan(mes, body, banreason, CFlags, &MFlags, UI.UniqID)) {
+		case MSG_CHK_ERROR_PASSED:
+			break;
+		default:
+			return code;
+	}
+
+	/* increase postcount if posting as registred user */
+	if(Uind != 0xFFFFFFFF) {
+		if(!uprof) uprof = new CProfiles();	// if it's logged in user
+		
+		UI.postcount++;
+		UI.lastIP = mes->IPAddr;
+		UI.LoginDate = time(NULL);
+		
+		if(uprof->SetUInfo(Uind, &UI) == 0) {
+			delete uprof;
+#if ENABLE_LOG >= 1
+		print2log("Call to CProfiles::SetUInfo failed at DB_Base::DB_InsertMessage(), line %d (Update user information for %s)",
+		    __LINE__, UI.username);
+#endif
+			printhtmlerror();
+		}
+	}
+	if(uprof != NULL) delete uprof;
+
+
+	if(*body != NULL && **body != 0) msize = (WORD)(strlen(*body) + 1);
+	else {
+		msize = 0;
+	}
+
+	// tuning some columns of the message stucture
+	mes->Readed = 0;
+	mes->msize = msize;
+	mes->Level = 0;
+	mes->Flag = 0;
+	mes->ParentThread = 0;
+
+	/************ set flags of message ************/
+	/* tune [pic] [url] message flags and other message flags */
+	mes->Flag = mes->Flag | MFlags;
+
+	// set "signed" flag
+	if(msigned && (CFlags & MSG_CHK_DISABLE_SIGNATURE) == 0)
+		mes->Flag |= MESSAGE_WAS_SIGNED;
+	
+	if(msize > 0) mes->Flag |= MESSAGE_HAVE_BODY;
+
+	if((CFlags & MSG_CHK_ENABLE_EMAIL_ACKNL) && Uind != 0xFFFFFFFF)
+		mes->Flag |= MESSAGE_MAIL_NOTIFIATION;
+	/**********************************************/
+
+	// tune message level and parent thread, if it's reply
+	// *** NEW *** : also tune Topic (if only one topic per thread supported)
+	if(root != 0) {
+		DWORD viroot = root;
+		re = 1; // set "reply" flag
+
+		// get real index
+		root = TranslateMsgIndex(root);
+		if(root == NO_MESSAGE_CODE) return MSG_CHK_ERROR_INVALID_REPLY;
+		
+		// read parent message
+		if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+		msg = (SMessage *)malloc(sizeof(SMessage));
+		if(wcfseek(fm, root, SEEK_SET) == -1) printhtmlerror();
+		if(!fCheckedRead(msg, sizeof(SMessage), fm)) printhtmlerror();
+		wcfclose(fm);
+
+		// check whether post is allowed
+		if((UI.right & USERRIGHT_SUPERUSER) == 0 && (msg->Flag & MESSAGE_IS_CLOSED)) {
+			free(msg);
+			return MSG_CHK_ERROR_CLOSED;
+		}
+
+		// tune level of message
+		mes->Level = (WORD)(msg->Level + 1);
+
+		// tune parent thread
+		if(msg->Level > 0)
+			mes->ParentThread = msg->ParentThread;
+		else
+			mes->ParentThread = root;
+
+		// tune topic
+		mes->Topics = msg->Topics;
+
+		// tune flags (inheritance)
+		mes->Flag |= ((msg->Flag & (MESSAGE_IS_INVISIBLE | MESSAGE_COLLAPSED_THREAD | MESSAGE_IS_CLOSED)));
+
+		// send mail ackn if required
+		{
+			// 1. Get user and email
+			CProfiles prof;
+			SProfile_UserInfo ui;
+			SProfile_FullUserInfo fui;
+			char subj[1000];
+			char bdy[100000];
+
+			fui.AboutUser = NULL;
+
+			if(msg->UniqUserID != 0 && prof.GetUserByName(msg->AuthorName, &ui, &fui, NULL) == PROFILE_RETURN_ALLOK &&
+				((msg->Flag & MESSAGE_MAIL_NOTIFIATION) || (ui.Flags & PROFILES_FLAG_ALWAYS_EMAIL_ACKN)) ) {
+				char *pb, *pb1, *pb2;
+				DWORD tmp;
+
+				DWORD flags = MESSAGE_ENABLED_TAGS;
+
+				if(!PrepareTextForPrint(mes->MessageHeader, &pb, mes->SecHeader, flags | BOARDTAGS_CUT_TAGS)) {
+					pb = (char*)malloc(strlen(mes->MessageHeader) + 1);
+					strcpy(pb, mes->MessageHeader);
+				}
+				
+				sprintf(subj, MAILACKN_REPLY_SUBJECT, pb);
+				free(pb);
+
+				if(!PrepareTextForPrint(mes->MessageHeader, &pb, mes->SecHeader, flags | mes->Flag | BOARDTAGS_EXPAND_ENTER)) {
+					pb = (char*)malloc(strlen(mes->MessageHeader) + 1);
+					strcpy(pb, mes->MessageHeader);
+				}
+				if(!PrepareTextForPrint(msg->MessageHeader, &pb1, mes->SecHeader, flags | mes->Flag | BOARDTAGS_EXPAND_ENTER)) {
+					pb1 = (char*)malloc(strlen(msg->MessageHeader) + 1);
+					strcpy(pb1, msg->MessageHeader);
+				}
+				if(!PrepareTextForPrint(*body, &pb2, mes->Security, flags | mes->Flag | BOARDTAGS_EXPAND_ENTER | BOARDTAGS_PURL_ENABLE)) {
+					pb2 = (char*)malloc(strlen(*body) + 1);
+					strcpy(pb2, *body);
+				}
+				
+				sprintf(bdy, MAILACKN_REPLY_BODY, msg->AuthorName, mes->AuthorName, pb1,  pb, pb2, viroot);
+				
+				wcSendMail(fui.Email, subj, bdy);
+
+				print2log("Mailackn was sent to %s", fui.Email);
+
+				free(pb);
+				free(pb1);
+				free(pb2);
+			}
+			if(fui.AboutUser) free(fui.AboutUser);
+		}
+		free(msg);
+	}
+	else {
+		re = 0;
+	}
+	
+	if((fb = wcfopen(F_MSGBODY, FILE_ACCESS_MODES_RW)) == NULL)
+		printhtmlerrorat(LOG_UNABLETOLOCATEFILERW, F_MSGBODY);
+	// ******* lock fb *******
+	lock_file(fb);
+
+	// get free space and set file pointer
+	CFreeDBFile fdb(F_FREEMBODY, 0);
+	if(fdb.errnum != FREEDBFILE_ERROR_ALLOK) {
+		unlock_file(fb);
+		printhtmlerrorat(LOG_UNABLETOCREATEFILE, F_FREEMBODY);
+	}
+	if((rd = fdb.AllocFreeSpace(msize)) == 0xFFFFFFFF) {
+		if(fdb.errnum != FREEDBFILE_ERROR_ALLOK) {
+			unlock_file(fb);
+			printhtmlerrorat(LOG_UNABLETOCREATEFILE, F_FREEMBODY);
+		}
+		
+		if(wcfseek(fb, 0, SEEK_END) != 0) {
+			unlock_file(fb);
+			printhtmlerror();
+		}
+		rd = wcftell(fb);
+		// in case if file is empty, to avoid msg_id=0
+		if (rd == 0){
+			if(!fCheckedWrite(&rd, sizeof(DWORD), fb)) {
+				unlock_file(fb);
+				printhtmlerror();
+			}
+			rd = wcftell(fb);
+		}
+	}
+	else {
+		if(fdb.errnum != FREEDBFILE_ERROR_ALLOK) {
+			unlock_file(fb);
+			printhtmlerror();
+		}
+		if(wcfseek(fb, rd, SEEK_SET) != 0) {
+			unlock_file(fm);
+			printhtmlerror();
+		}
+	}
+	
+	// set index of body
+	mes->MIndex = rd;
+	if(!fCheckedWrite(*body, msize, fb)) {
+		unlock_file(fb);
+		printhtmlerror();
+	}
+	
+	unlock_file(fb);
+	// ******* unlock fb *******
+
+	wcfclose(fb);
+
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+		printhtmlerror();
+	// ****** lock fm ******
+	lock_file(fm);
+	
+	// Allocate space for message header and save message index
+	CFreeDBFile fdb1(F_FREEINDEX, sizeof(SMessage)); // Wasted block = sizeof(SMessage)
+	if(fdb1.errnum != FREEDBFILE_ERROR_ALLOK) {
+		unlock_file(fm);
+		printhtmlerrorat(LOG_UNABLETOCREATEFILE, F_FREEINDEX);
+	}
+	if((fp = fdb1.AllocFreeSpace(sizeof(SMessage))) == 0xFFFFFFFF) {
+		if(fdb1.errnum != FREEDBFILE_ERROR_ALLOK) {
+			unlock_file(fm);
+			printhtmlerrorat(LOG_UNABLETOCREATEFILE, F_FREEINDEX);
+		}
+
+		if(wcfseek(fm, 0, SEEK_END) != 0) {
+			unlock_file(fm);
+			printhtmlerror();
+		}
+		fp = wcftell(fm);
+		// in case if file is empty, to avoid msg_id=0
+		if (fp == 0){
+			if(!fCheckedWrite(&fp, sizeof(DWORD), fm)) {
+				unlock_file(fm);
+				printhtmlerror();
+			}
+			fp = wcftell(fm);
+		}
+
+	}
+	else {
+		if(fdb1.errnum != FREEDBFILE_ERROR_ALLOK) {
+			unlock_file(fb);
+			printhtmlerror();
+		}
+		if(wcfseek(fm, fp, SEEK_SET) != 0) {
+			unlock_file(fm);
+			printhtmlerror();
+		}
+	}
+
+	// get msg index for new entry
+	ri = AddMsgIndex(fp);
+	// tune ViIndex in msg
+	mes->ViIndex = ri;
+	// write mes
+	if(!fCheckedWrite(mes, sizeof(SMessage), fm)) {
+		unlock_file(fm);
+		printhtmlerror();
+	}
+	
+	unlock_file(fm);
+	// ****** unlock fm ******
+	wcfclose(fm);
+
+	if((fi = wcfopen(F_INDEX, FILE_ACCESS_MODES_RW)) == NULL)
+		printhtmlerror();
+	// ****** lock fi ******
+	lock_file(fi);
+
+	// find index of root message
+	if(re) {
+		// temporary !!! should be added index support
+		if(wcfseek(fi, 0, SEEK_END) != 0) {
+			unlock_file(fi);
+			printhtmlerror();
+		}
+
+		fisize = fl = wcftell(fi);
+		buf = (SMessageTable *)malloc((sizeof(SMessageTable)*READ_MESSAGE_TABLE) + 1);
+
+		while(fl > 0) {
+			DWORD toread;
+			if(fl >= READ_MESSAGE_TABLE*sizeof(SMessageTable)) {
+				fl = fl - READ_MESSAGE_TABLE*sizeof(SMessageTable);
+				toread = READ_MESSAGE_TABLE*sizeof(SMessageTable);
+			}
+			else {
+				toread = fl;
+				fl = 0;
+			}
+		
+			if(wcfseek(fi, fl, SEEK_SET) != 0) {
+				unlock_file(fi);
+				printhtmlerror();
+			}
+			
+			if(!fCheckedRead(buf, toread, fi)) {
+				unlock_file(fi);
+				printhtmlerror();
+			}
+	
+			rd = i = (toread + 1) / sizeof(SMessageTable) - 1;
+			while(i>=0) {
+				if(M_IN(root, buf[i].begin, buf[i].end) || M_IN(root, buf[i].end, buf[i].begin)) {
+					goto LB_end;
+				}
+				i--;
+			}
+		}
+		// NO MESSAGE
+#if _DEBUG_ == 1
+		print2log("Incorrect message DB - message not found");
+#endif
+		unlock_file(fi);
+		wcfclose(fi);
+		printhtmlerror();
+		// --------------------------------------------
+
+LB_end:
+		tmp = malloc(fisize - fl + 10);
+		if(wcfseek(fi, fl + ((i+1)*sizeof(SMessageTable)), SEEK_SET) == -1) {
+			unlock_file(fi);
+			printhtmlerror();
+		}
+		// read end part of WCFILE
+		DWORD readed;
+		readed = wcfread(tmp, 1, fisize - fl + 10, fi);
+		if(!wcfeof(fi)) {
+			unlock_file(fi);
+			printhtmlerror();
+		}
+		if(wcfseek(fi, fl + (i*sizeof(SMessageTable)), SEEK_SET) == -1) {
+			unlock_file(fi);
+			printhtmlerror();
+		}
+		if(buf[i].end < buf[i].begin) {
+			// write indexes up to message before root
+			fl = buf[i].begin;
+			if(buf[i].end < root) {
+				buf[i].begin = root - 1;
+				if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+					unlock_file(fi);
+					printhtmlerror();
+				}
+			}
+			if(root + sizeof(SMessage) == fp) {
+				// can join two messages with backward style
+				buf[i].begin = root;
+				buf[i].end = fp + sizeof(SMessage) - 1;
+				if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+					unlock_file(fi);
+					printhtmlerror();
+				}
+			}
+			else {			
+				// write new message index
+				buf[i].begin = fp;
+				buf[i].end = fp + sizeof(SMessage) - 1;
+				if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+					unlock_file(fi);
+ 					printhtmlerror();
+				}
+				// write last messages
+				buf[i].begin = fl;
+				buf[i].end = root;
+				if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+					unlock_file(fi);
+					printhtmlerror();
+				}						
+			}
+		}
+		else {
+			if((buf[i].end + 1 == fp) && (root + sizeof(SMessage) == fp)) {
+				buf[i].end = fp + sizeof(SMessage) - 1;
+				if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+					unlock_file(fi);
+					printhtmlerror();
+				}
+			}
+			else {
+				fl = buf[i].begin;
+				if(buf[i].end + 1 != root + sizeof(SMessage)) {
+					// write indexes up to root
+					buf[i].begin = root + sizeof(SMessage);
+					if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+						unlock_file(fi);
+						printhtmlerror();
+					}
+				}
+				// write new message index
+				buf[i].begin = fp;
+				buf[i].end = fp + sizeof(SMessage) - 1;
+				if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+					unlock_file(fi);
+					printhtmlerror();
+				}
+				// write last messages
+				buf[i].begin = fl;
+				buf[i].end = root + sizeof(SMessage) - 1;
+				if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+					unlock_file(fi);
+					printhtmlerror();
+				}
+			}
+		}
+		// write end part of WCFILE
+		if(!fCheckedWrite(tmp, readed, fi)) {
+			unlock_file(fi);
+			printhtmlerror();
+		}
+		free(tmp);
+	}
+	else {
+
+		// Increment main thread count
+		IncrementMainThreadCount();
+
+		DWORD fpos;
+		if(wcfseek(fi, 0, SEEK_END) != 0) {
+			unlock_file(fi);
+			printhtmlerror();
+		}
+		fpos = wcftell(fi);
+		
+		buf = (SMessageTable *)malloc(sizeof(SMessageTable));
+
+		if(fpos > 0) {
+			// try to join message
+			fpos -= sizeof(SMessageTable);
+			if(wcfseek(fi, fpos, SEEK_SET) != 0) {
+				unlock_file(fi);
+				printhtmlerror();
+			}
+			if(!fCheckedRead(buf, sizeof(SMessageTable), fi)) {
+				unlock_file(fi);
+				printhtmlerror();
+			}
+			if((buf->begin > buf->end) && (buf->begin + 1 == fp)) {
+				buf->begin += sizeof(SMessage);
+			}
+			else {
+				if(((buf->end - buf->begin + 1)/sizeof(SMessage) == 1) && (buf->end + 1 == fp)) {
+					buf->end = buf->begin;
+					buf->begin = fp - 1 + sizeof(SMessage);
+				}
+				else {
+					buf->begin = fp;
+					buf->end = fp + sizeof(SMessage) - 1;
+					fpos += sizeof(SMessageTable);
+				}
+			}
+		}
+		else {
+			// no join - just put it at the end of WCFILE
+			buf->begin = fp;
+			buf->end = fp + sizeof(SMessage) - 1;
+			//fpos += sizeof(SMessageTable);
+		}
+
+		if(wcfseek(fi, fpos, SEEK_SET) != 0) printhtmlerror();
+
+		if(!fCheckedWrite(buf, sizeof(SMessageTable), fi)) {
+			unlock_file(fi);
+			printhtmlerror();
+		}
+	}
+
+	// close all files and clean garbage database
+	unlock_file(fi);
+	// ****** unlock fi ******
+
+	wcfclose(fi);
+	free(buf);
+	return MSG_CHK_ERROR_PASSED;
+}
+
+// delete messages with Level >= root.Level
+// return 1 if successful, otherwise 0
+int DB_Base::DB_DeleteMessages(DWORD root)
+{
+	DWORD rr;
+	DWORD *msgsel;
+	DWORD count;
+	// select messages in root thread
+	if(!SelectMessageThreadtoBuf(root, &msgsel, &count)) return 0;
+	// delete selected messages
+	for(rr = 0; rr < count; rr++) {
+		DB_DeleteMessage(msgsel[rr]);
+	}
+	free(msgsel);
+	return 1;
+}
+
+// return 1 if successfull, 0 otherwise
+int DB_Base::DB_DeleteMessage(DWORD root)
+{
+	SMessage msg;
+	SMessageTable *buf;
+	DWORD fbsize, fbindex, oldroot;
+	DWORD fl, fisize, rd;
+	int i;
+	void *tmp;
+	oldroot = root;
+	root = TranslateMsgIndex(root);
+	if(root == NO_MESSAGE_CODE) return 0;
+
+	//*******************************************
+	//	Transaction should be started here
+	//*******************************************
+
+	//	Delete message reference
+	if(DeleteMsgIndex(oldroot) == 0) return 0;
+	//	Read message and save index of body and body size
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_RW)) == NULL) printhtmlerror();
+	if(wcfseek(fm, root, SEEK_SET) < 0) printhtmlerror();
+	if(!fCheckedRead(&msg, sizeof(SMessage), fm)) printhtmlerror();
+	wcfclose(fm);
+	fbsize = msg.msize;
+	fbindex = msg.MIndex;
+	//	Decrement thread count if it's main thread message
+	if(msg.Level == 0) DecrementMainThreadCount();
+	
+	buf = (SMessageTable *)malloc(sizeof(SMessageTable)*READ_MESSAGE_TABLE + 1);
+	
+	// drop index in FI_INDEX
+	
+	if((fi = wcfopen(F_INDEX, FILE_ACCESS_MODES_RW)) == NULL) {
+		printhtmlerror();
+	}
+	// ****** lock fi ******
+	lock_file(fi);
+
+	// find index of root message
+	// temporary !!! should be added index support
+	if(wcfseek(fi, 0, SEEK_END) != 0) {
+		unlock_file(fi);
+		printhtmlerror();
+	}
+	fisize = fl = wcftell(fi);
+	while(fl > 0) {
+		DWORD toread;
+		if(fl >= READ_MESSAGE_TABLE*sizeof(SMessageTable)) {
+			fl = fl - READ_MESSAGE_TABLE*sizeof(SMessageTable);
+			toread = READ_MESSAGE_TABLE*sizeof(SMessageTable);
+		}
+		else {
+			toread = fl;
+			fl = 0;
+		}
+		if(wcfseek(fi, fl, SEEK_SET) != 0) {
+			unlock_file(fi);
+			printhtmlerror();
+		}
+		if(!fCheckedRead(buf, toread, fi)) {
+			unlock_file(fi);
+			printhtmlerror();
+		}
+		rd = i = (toread + 1) / sizeof(SMessageTable) - 1;
+		while(i>=0) {
+			if(M_IN(root, buf[i].begin, buf[i].end) || M_IN(root, buf[i].end, buf[i].begin)) {
+				goto LB_MsgFound;
+			}
+			i--;
+		}
+	}
+	// not found message
+	unlock_file(fi);
+	printhtmlerror();
+
+LB_MsgFound:
+	
+	tmp = malloc(fisize - fl + 10);
+	if(wcfseek(fi, fl + ((i+1)*sizeof(SMessageTable)), SEEK_SET) != 0) {
+		unlock_file(fi);
+		printhtmlerror();
+	}
+	// read end part of WCFILE
+	DWORD readed;
+	readed = wcfread(tmp, 1, fisize - fl + 10, fi);
+	if(!wcfeof(fi)) {
+		unlock_file(fi);
+		printhtmlerror();
+	}
+	if(wcfseek(fi, fl + (i*sizeof(SMessageTable)), SEEK_SET) != 0) {
+		unlock_file(fi);
+		printhtmlerror();
+	}
+	
+	oldroot = 0;
+	if(buf[i].end < buf[i].begin) {
+		// write indexes up to message before root
+		fl = buf[i].begin;
+		if(buf[i].end < root) {
+			oldroot = 1;
+			buf[i].begin = root - 1;
+			if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+				oldroot = 1; 			
+				unlock_file(fi);
+				printhtmlerror();
+			}
+		}
+		// write last messages
+		buf[i].begin = fl;
+		buf[i].end = root + sizeof(SMessage);
+		if(buf[i].begin + 1 != buf[i].end) {
+			oldroot = 1;
+			if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+				unlock_file(fi);
+				printhtmlerror();
+			}
+		}
+	}
+	else {
+		fl = buf[i].begin;
+		if(buf[i].end + 1 != root + sizeof(SMessage)) {
+			oldroot = 1;
+			// write indexes up to root
+			buf[i].begin = root + sizeof(SMessage);
+			if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+				unlock_file(fi);
+				printhtmlerror();
+			}
+		}
+		// write last messages
+		buf[i].begin = fl;
+		buf[i].end = root - 1;
+		if(buf[i].begin < buf[i].end) {
+			oldroot = 1;
+			if(!fCheckedWrite(&buf[i], sizeof(SMessageTable), fi)) {
+				unlock_file(fi);
+				printhtmlerror();
+			}
+		}
+	}
+
+	if(!fCheckedWrite(tmp, readed, fi)) {
+		unlock_file(fi);
+		printhtmlerror();
+	}
+
+	free(tmp);
+
+	if(!oldroot) fisize-=sizeof(SMessageTable);
+	
+#ifdef WIN32	
+	if(!oldroot) if(wctruncate(fi, fisize) != 0) {
+#else
+	if(!oldroot) if(truncate(F_INDEX, fisize) != 0) {
+#endif
+		unlock_file(fi);
+		printhtmlerror();
+	}
+
+	unlock_file(fi);
+	// ****** unlock fi *******
+	wcfclose(fi);
+	
+	free(buf);
+	
+	// mark messages as free space
+	CFreeDBFile fdb(F_FREEINDEX, 0); // there is no wasted block !
+	if(fdb.errnum != FREEDBFILE_ERROR_ALLOK)
+		printhtmlerror();
+	if(fdb.MarkFreeSpace(root, sizeof(SMessage)) != FREEDBFILE_ERROR_ALLOK)
+		printhtmlerror();
+	
+	// free fb space
+	CFreeDBFile fdb1(F_FREEMBODY, 0);
+	if(fdb1.errnum != FREEDBFILE_ERROR_ALLOK)
+		printhtmlerror();
+	if(fdb1.MarkFreeSpace(fbindex, fbsize) != FREEDBFILE_ERROR_ALLOK)
+		printhtmlerror();
+	
+	return 1;
+}
+
+int DB_Base::DB_ChangeMessage(DWORD root, SMessage *nmsg, char **body, WORD msize,
+							  DWORD CFlags, char **banreason)
+{
+	int i;
+	DWORD RFlags;
+	DWORD omsize;
+	WCFILE *fm;
+
+	root = TranslateMsgIndex(root);
+	if(root == NO_MESSAGE_CODE) return 0;
+
+	// message header, banned address and spelling message check
+	switch (i = CheckSpellingBan(nmsg, body, banreason, CFlags, &RFlags)) {
+	case MSG_CHK_ERROR_PASSED: break;
+	default: return i;
+	}
+
+	// tuning some columns of message stucture (first stage)
+	omsize = nmsg->msize;
+
+	// save new message size
+	if(*body != NULL && **body != 0) nmsg->msize = (WORD)(strlen(*body) + 1);
+	else {
+		nmsg->msize = 0;
+	}
+
+	/************ set flags of message ************/
+	/* tune [pic] [url] message flags and other message flags */
+	nmsg->Flag = nmsg->Flag | RFlags;
+
+	// set "signed" flag
+//	if(msigned && (CFlags & MSG_CHK_DISABLE_SIGNATURE) == 0)
+//		nmsg->Flag |= MESSAGE_WAS_SIGNED;
+
+	if(msize > 0) nmsg->Flag |= MESSAGE_HAVE_BODY;
+	else nmsg->Flag &= (~MESSAGE_HAVE_BODY);
+
+	if((CFlags & MSG_CHK_ENABLE_EMAIL_ACKNL) && ULogin.LU.ID[0] != 0xFFFFFFFF)
+		nmsg->Flag |= MESSAGE_MAIL_NOTIFIATION;
+
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+		printhtmlerror();
+
+	// ********* lock FM *********
+	lock_file(fm);
+
+	if(wcfseek(fm, root, SEEK_SET) != 0) {
+		unlock_file(fm);
+		printhtmlerror();
+	}
+
+	// enought size for write new body ?
+	if(nmsg->msize > omsize) {
+		// No, it's a pity we need to reallocate free space
+
+		// mark body of message as free space
+		CFreeDBFile fdb(F_FREEMBODY, 0);
+		if(fdb.errnum != FREEDBFILE_ERROR_ALLOK) {
+			unlock_file(fm);
+			printhtmlerror();
+		}
+		if(fdb.MarkFreeSpace(nmsg->MIndex, omsize) != FREEDBFILE_ERROR_ALLOK) {
+			unlock_file(fm);
+			printhtmlerror();
+		}
+		
+		// write new body
+		if((fb = wcfopen(F_MSGBODY, FILE_ACCESS_MODES_RW)) == NULL) {
+			unlock_file(fm);
+			printhtmlerror();
+		}
+		// ********* lock fb *********
+		lock_file(fb);
+
+		// get free space and set WCFILE pointer
+		if((nmsg->MIndex = fdb.AllocFreeSpace(msize)) == 0xFFFFFFFF) {
+			// no free space - allocate it at the end of WCFILE
+			if(fdb.errnum != FREEDBFILE_ERROR_ALLOK) {
+				unlock_file(fm);
+				unlock_file(fb);
+				printhtmlerror();
+			}
+			
+			if(wcfseek(fb, 0, SEEK_END) != 0) {
+				unlock_file(fm);
+				unlock_file(fb);
+				printhtmlerror();
+			}
+			nmsg->MIndex = wcftell(fb);
+		}
+		else {
+			// free space found
+			if(wcfseek(fb, nmsg->MIndex, SEEK_SET) != 0) {
+				unlock_file(fm);
+				unlock_file(fb);
+				printhtmlerror();
+			}
+		}
+
+		if(!fCheckedWrite(*body, nmsg->msize, fb)) {
+			unlock_file(fb);
+			unlock_file(fm);
+			printhtmlerror();
+		}
+		unlock_file(fb);
+		// ******* unlock fb *******
+		wcfclose(fb);
+		
+	}
+	else {
+		// if the body present write it
+		if(nmsg->msize) {
+			if((fb = wcfopen(F_MSGBODY, FILE_ACCESS_MODES_RW)) == NULL) {
+				unlock_file(fm);
+				printhtmlerror();
+			}
+			// ********* lock fb *********
+			lock_file(fb);
+
+			if(wcfseek(fb, nmsg->MIndex, SEEK_SET) != 0) {
+				unlock_file(fb);
+				unlock_file(fm);
+				printhtmlerror();
+			}
+			if(!fCheckedWrite(*body, nmsg->msize, fb)) {
+				unlock_file(fb);
+				unlock_file(fm);
+				printhtmlerror();
+			}
+			unlock_file(fb);
+			// ******** unlock fb ********
+			wcfclose(fb);
+		}
+
+		// more or equal to sizeof(SMessageBody) will left free?
+		if(nmsg->msize < omsize) {
+			// mark it as free space
+			CFreeDBFile fdb(F_FREEMBODY, 0);
+			if(fdb.errnum != FREEDBFILE_ERROR_ALLOK) {
+				unlock_file(fm);
+				printhtmlerror();
+			}
+			if(fdb.MarkFreeSpace(nmsg->MIndex + nmsg->msize,
+				omsize - nmsg->msize) != FREEDBFILE_ERROR_ALLOK)
+			{
+				unlock_file(fm);
+				printhtmlerror();
+			}
+		}
+	}
+	
+	// write message header
+	if(!fCheckedWrite(nmsg, sizeof(SMessage), fm)) {
+		unlock_file(fm);
+		printhtmlerror();
+	}
+	
+	unlock_file(fm);
+	// unlock FM semaphore
+	
+	wcfclose(fm);
+
+	return 1;
+}
+
+/* Print message with body
+ */
+int DB_Base::PrintHtmlMessageBody(SMessage *msg, char *body)
+{
+	char *an, *pb, *ps = NULL;
+	DWORD tmp;
+	DWORD flg;
+	CProfiles prof;
+#if SHOW_HOST_NAME
+	int showhost = 1;
+#else
+	int showhost = 0;
+#endif
+
+	if((currentdsm & 1) == 0) flg = MESSAGE_ENABLED_TAGS | MESSAGE_ENABLED_SMILES;
+	else flg = MESSAGE_ENABLED_TAGS;
+
+	if(FilterBoardTags(msg->MessageHeader, &an, msg->SecHeader,
+		MAX_PARAMETERS_STRING, flg, &tmp) == 1) {
+
+	}
+	else an = (char*)&(msg->MessageHeader);
+
+	if(msg->msize > 0) {
+		DWORD flg = msg->Flag | MESSAGE_ENABLED_SMILES | BOARDTAGS_PURL_ENABLE;
+		if((currentdsm & 1) != 0) flg = flg & (~MESSAGE_ENABLED_SMILES);
+		
+		if(FilterBoardTags(body, &pb, msg->Security, MAX_PARAMETERS_STRING, flg | BOARDTAGS_EXPAND_ENTER, &tmp) == 0)
+			pb = body;
+	}
+	if(msg->Flag & MESSAGE_WAS_SIGNED) {
+		SProfile_UserInfo ui;
+		SProfile_FullUserInfo fui;
+		if(prof.GetUserByName(msg->AuthorName, &ui, &fui, NULL) == PROFILE_RETURN_ALLOK &&
+			msg->UniqUserID == ui.UniqID)
+		{
+			if(strlen(fui.Signature) > 0) {
+				// first of all - let's filter HTML !
+				char *st = FilterHTMLTags(fui.Signature, MAX_PARAMETERS_STRING);
+				if(st) {
+					if(FilterBoardTags(st, &ps, msg->Security, MAX_PARAMETERS_STRING,
+						flg | BOARDTAGS_EXPAND_ENTER, &tmp) == 0)
+					{
+						ps = (char*)malloc(strlen(st) + 1);
+						strcpy(ps, st);
+					}
+					free(st);
+				}
+			}
+		}
+	}
+
+	printf(DESIGN_VIEW_THREAD_MSG_HEADER);
+
+#if TOPICS_SYSTEM_SUPPORT
+	// print topic info
+	SMessage parmes;
+	if(msg->ParentThread != 0 && msg->ParentThread != NO_MESSAGE_CODE) {
+		if(!ReadDBMessage(msg->ParentThread, &parmes)) {
+			// database error - invalid parent thread
+			printhtmlerror();
+		}
+	}
+	else {
+		memcpy(&parmes, msg, sizeof(SMessage));
+	}
+
+	if( parmes.Topics >= 0 && parmes.Topics < TOPICS_COUNT)
+			printf(DESIGN_VIEW_THREAD_TOPIC, Topics_List[parmes.Topics]);
+	else printf(DESIGN_VIEW_THREAD_TOPIC, Topics_List[0]);
+
+#endif
+
+	printf("<BIG>%s</BIG>", an);
+
+#ifdef USER_FAVOURITES_SUPPORT
+	{
+		
+		DWORD favtemp;
+#if USER_FAVOURITES_SUPPORT == 2
+		favtemp = parmes.ViIndex;
+#else
+		favtemp = msg->ViIndex;
+#endif
+		if (ULogin.LU.ID[0] != 0){
+			DWORD result = prof.CheckandAddFavsList(ULogin.LU.SIndex, favtemp, 0);
+			switch(result) {
+				case PROFILE_RETURN_ALLOK:
+					printf("&nbsp;&nbsp;&nbsp;<A HREF=\"" MY_CGI_URL "?favadd=%ld\" target=_blank>"
+					DESIGN_FAVORITES_ADD_THREAD "</A>", favtemp);
+					break;
+				case PROFILE_RETURN_ALREADY_EXIST:
+					printf("&nbsp;&nbsp;&nbsp;<A HREF=\"" MY_CGI_URL "?favdel=%ld\" target=_blank>"
+					DESIGN_FAVORITES_DEL_THREAD "</A>", favtemp);
+					break;
+				case PROFILE_RETURN_UNKNOWN_ERROR:
+					//printf(DESIGN_VIEW_THREAD_MSG_FAVNO);
+					break;
+			}
+		}
+	}
+#endif
+
+#if TOPICS_SYSTEM_SUPPORT
+	// if we are not in preview mode and have admin right - let's print topic change form
+	if( ((ULogin.LU.right & USERRIGHT_SUPERUSER) ||			// modification by admin
+		(ULogin.LU.ID[0] != 0 && msg->UniqUserID == ULogin.LU.UniqID &&
+		(ULogin.LU.right & USERRIGHT_MODIFY_MESSAGE))) &&	// own message by user
+		(msg->ParentThread != NO_MESSAGE_CODE)
+		)
+	{
+		// print change topic form
+		printf("\n<FORM><INPUT TYPE=HIDDEN NAME=\"ChangeTopic\" VALUE=\"%ld\">"
+			"<SELECT NAME=\"topic\">", parmes.ViIndex);
+		for(DWORD i = 0; i < TOPICS_COUNT; i++) {
+			if(Topics_List_map[i] == msg->Topics) {
+				// define default choise
+				printf("<OPTION VALUE=\"%d\"" LISTBOX_SELECTED ">%s\n", 
+					Topics_List_map[i], Topics_List[Topics_List_map[i]]);
+			}
+			else {
+				printf("<OPTION VALUE=\"%d\">%s\n", 
+					Topics_List_map[i], Topics_List[Topics_List_map[i]]);
+			}
+		}
+		printf("</SELECT>&nbsp;&nbsp;<INPUT TYPE=SUBMIT NAME=\"ChangeTopic\" VALUE=\"Change\"></FORM>\n");
+	}
+#endif
+
+	/* potential BUG here */
+	char *aname = (char*)malloc(1000);
+	Profile_UserName(msg->AuthorName, aname, msg->UniqUserID, 0);
+
+	printf(DESIGN_VIEW_THREAD_MSG_SENT, MESSAGEMAIN_viewthread_sent, aname);
+
+	free(aname);
+
+	// print host name if requred
+	if(showhost || (ULogin.LU.right & USERRIGHT_SUPERUSER)) {
+		char tmp[10000], tmp2[100];
+		unsigned char *aa = (unsigned char *)(&msg->IPAddr);
+		strcpy(tmp, msg->HostName);
+		//	print IP in numeric format for administrator
+		if((ULogin.LU.right & USERRIGHT_SUPERUSER) != 0) {
+			strcat(tmp, MESSAGEMAIN_viewthread_ipview);
+			sprintf(tmp2, "%u.%u.%u.%u", aa[0] & 0xff, aa[1] & 0xff, aa[2] & 0xff, aa[3] & 0xff);
+			strcat(tmp, tmp2);
+		}
+		printf(DESIGN_VIEW_THREAD_MSG_SENT2, tmp);
+	}
+
+	char *dt = ConvertFullTime((time_t)msg->Date);
+	printf(DESIGN_VIEW_THREAD_DATE, MESSAGEMAIN_viewthread_date, dt);
+	if(msg->MDate) {
+		dt = ConvertFullTime((time_t)msg->MDate);
+		printf(DESIGN_VIEW_THREAD_MDATE, MESSAGEMAIN_viewthread_mdate, dt);
+	}
+
+	printf(DESIGN_VIEW_THREAD_MSG_SENT3);
+
+	//	Print body
+	if(msg->msize > 0) {
+		printf(DESIGN_VIEW_THREAD_BODY, pb);
+	}
+	else printf(DESIGN_VIEW_THREAD_BODY, "");
+
+	//	Print signature
+	if(ps) {
+		if((currentdsm & 0x80) == 0) {
+			printf(DESIGN_VIEW_THREAD_SIGN, ps);
+		}
+		else {
+			printf(DESIGN_VIEW_THREAD_SIGN, MESSAGEMAIN_viewthread_sigdisabled);
+		}
+		free(ps);
+	}
+
+	printf("<P></P><BR>");
+	if(an != (char*)&(msg->MessageHeader)) free(an);
+	if(msg->msize > 0 && pb != body) free(pb);
+	return 0;
+}
+
+// return 1 if valid, 0 otherwise
+int DB_Base::DB_PrintMessageBody(DWORD root)
+{
+	SMessage msg;
+	char *body;
+	DWORD readed;
+
+	//	Superuser access will not increment read count
+	bool NeedReadedIncrement = ((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0) &&
+		(CheckReadValidity(Nip, root));
+
+	//	Get real index
+	root = TranslateMsgIndex(root);
+	if(root ==  NO_MESSAGE_CODE) return 0;
+	
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+		printhtmlerror();
+	
+	
+	// --- lock F_MSGINDEX file ---
+	if(NeedReadedIncrement) lock_file(fm);
+	
+	if(wcfseek(fm, root, SEEK_SET) != 0)
+	{
+		if(NeedReadedIncrement) unlock_file(fm);
+		printhtmlerror();
+	}
+	
+	if(!fCheckedRead(&msg, sizeof(SMessage), fm))
+	{
+		if(NeedReadedIncrement) unlock_file(fm);
+		printhtmlerror();
+	}
+
+	if(NeedReadedIncrement)
+	{
+		msg.Readed++;
+		if(wcfseek(fm, root, SEEK_SET) != 0)
+		{
+			unlock_file(fm);
+			printhtmlerror();
+		}
+		if(!fCheckedWrite(&msg, sizeof(SMessage), fm))
+		{
+			unlock_file(fm);
+			printhtmlerror();
+		}
+		unlock_file(fm);
+		wcfclose(fm);
+	}
+	// end of lock F_MSGINDEX file ---
+	
+	if((fb = wcfopen(F_MSGBODY, FILE_ACCESS_MODES_R)) == NULL)
+		printhtmlerrorat(LOG_UNABLETOLOCATEFILE, F_MSGBODY);
+	if(wcfseek(fb, msg.MIndex, SEEK_SET) == -1) printhtmlerror();
+	body = (char*)malloc(msg.msize + 10);
+	if((readed = wcfread(body, 1, msg.msize + 2, fb)) < msg.msize) printhtmlerror();
+	body[readed] = 0;
+	if(msg.msize != 0 && *body == 0) {
+	    char *ss = body;
+	    ss++;
+	    while(*ss) {
+		*(ss-1) = *(ss);
+		ss++;
+	    }
+	    *(ss-1) = *ss;
+	}
+	wcfclose(fb);
+	
+	PrintHtmlMessageBody(&msg, body);
+	return 1;
+}
+
+/* print messages thread begining from message root, if root is not first message in the thread,
+ * functions search for first message of the thread, and print thread from there
+ * return 1 if valid, 0 otherwise
+ */
+int DB_Base::DB_PrintMessageThread(DWORD root)
+{
+	SMessageTable *buf;
+	SMessage *msgs;
+	DWORD rr, fipos, toread;
+	DWORD fmpos, fl, oldroot;
+	DWORD fisize, rd;
+	int LastLevel = 0;
+	int i;
+	// translate virtual to real index, and check it
+	root = TranslateMsgIndex(root);
+	if(root == NO_MESSAGE_CODE) return 0; // invalid or nonexisting index
+	
+	buf = (SMessageTable *)malloc(sizeof(SMessageTable)*READ_MESSAGE_TABLE+1);
+	msgs = (SMessage *)malloc(sizeof(SMessage)*READ_MESSAGE_HEADER+1);
+	
+	// find where is main thread message
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+	if(wcfseek(fm, root, SEEK_SET) == -1) printhtmlerror();
+	if(!fCheckedRead(msgs, sizeof(SMessage), fm)) printhtmlerror();
+	
+	oldroot = msgs->ViIndex;
+	
+	if(msgs->Level != 0)
+		rr = msgs->ParentThread;
+	else
+		rr = root;
+
+	wcfclose(fm);
+	
+	/* set root index = index of main thread message */
+	root = rr;
+	
+	if((fi = wcfopen(F_INDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+	if(wcfseek(fi, 0, SEEK_END) == -1) printhtmlerror();
+	
+	/* temporary !!! should be added index support */
+	// find index in index file
+	fisize = fl = wcftell(fi);
+	
+	buf = (SMessageTable *)malloc(sizeof(SMessageTable)*READ_MESSAGE_TABLE + 1);
+	
+	while(fl > 0) {
+		DWORD toread;
+		if(fl >= READ_MESSAGE_TABLE*sizeof(SMessageTable)) {
+			fl = fl - READ_MESSAGE_TABLE*sizeof(SMessageTable);
+			toread = READ_MESSAGE_TABLE*sizeof(SMessageTable);
+		}
+		else {
+			toread = fl;
+			fl = 0;
+		}
+		if(wcfseek(fi, fl, SEEK_SET) == -1) printhtmlerror();
+		if(!fCheckedRead(buf, toread, fi)) printhtmlerror();
+		rd = i = (toread + 1) / sizeof(SMessageTable) - 1;
+		while(i>=0) {
+			if(M_IN(root, buf[i].begin, buf[i].end) || M_IN(root, buf[i].end, buf[i].begin)) {
+				goto PT_Found;
+			}
+			i--;
+		}
+	}
+	
+	// not found in indexes - fatal error
+	printhtmlerror();
+	
+PT_Found:
+	fl = fl + (i + 1)*sizeof(SMessageTable);
+	
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+	if(wcfseek(fi, fl, SEEK_SET) == -1) printhtmlerror();
+	
+	fipos = wcftell(fi);
+	
+	int czero = 0;
+	int bp = 0;
+	invflag = -1;
+	collapsed = 0;
+	
+	printf(MESSAGEMAIN_in_this_thread);
+	printf(DESIGN_open_dl);
+	
+	for(;;) {
+		if(fipos == 0) break;
+		else {
+			if(fipos >= READ_MESSAGE_TABLE*sizeof(SMessageTable)) {
+				toread = READ_MESSAGE_TABLE*sizeof(SMessageTable);
+				fipos = fipos - READ_MESSAGE_TABLE*sizeof(SMessageTable);
+			}
+			else {
+				toread = fipos;
+				fipos = 0;
+			}
+		}
+		if(wcfseek(fi, fipos, SEEK_SET) == -1) printhtmlerror();
+		if((rr = wcfread(buf, 1, toread, fi)) % sizeof(SMessageTable) != 0) printhtmlerror();
+		
+		signed long i = rr / sizeof(SMessageTable) - 1;
+		
+		while(i >= 0) {
+			if(buf[i].begin < buf[i].end ) {
+				// forward direction
+				fmpos = buf[i].begin;
+				if(!czero) fmpos = root;				
+				if(wcfseek(fm, fmpos, SEEK_SET) == -1) printhtmlerror();
+				while(fmpos != (buf[i].end + 1)) {
+					DWORD toread;
+					if(buf[i].end - fmpos < READ_MESSAGE_HEADER*sizeof(SMessage)) {
+						toread = buf[i].end - fmpos + 1;
+						fmpos = fmpos + toread;
+					}
+					else {
+						toread = READ_MESSAGE_HEADER*sizeof(SMessage);
+						fmpos = fmpos + toread;
+					}
+				    //if(strcmp(getenv(QUERY_STRING), "read=1695642") == 0)  
+					//  print4log("suxxxx: toread:%d, root:%d, fmpos:%d, beg:%d, end:%d", toread, root, fmpos, buf[i].begin, buf[i].end); 
+					if(!fCheckedRead(msgs, toread, fm)) printhtmlerror();
+					
+					LastLevel = printThreadbuffer(msgs, toread, PRINT_FORWARD, fmpos - toread, LastLevel,
+						&czero, oldroot, root, &bp);
+					if(czero == 2) goto PT_Finish;
+				}
+			}
+			else {
+				// backward direction
+				DWORD toread;
+				fmpos = buf[i].begin + 1;
+				while(fmpos != buf[i].end) {
+					if( fmpos - buf[i].end > READ_MESSAGE_HEADER*sizeof(SMessage)) {
+						fmpos = fmpos - READ_MESSAGE_HEADER*sizeof(SMessage);
+						toread = READ_MESSAGE_HEADER*sizeof(SMessage);
+					}
+					else {
+						toread = fmpos - buf[i].end;
+						fmpos = buf[i].end;
+					}
+					
+					if(wcfseek(fm, fmpos, SEEK_SET) == -1) printhtmlerror();
+					if(!fCheckedRead(msgs, toread, fm)) printhtmlerror();
+					
+					LastLevel = printThreadbuffer(msgs, toread, PRINT_BACKWARD, fmpos , LastLevel,
+						&czero, oldroot, root, &bp);
+					if(czero == 2) goto PT_Finish;
+				}
+			}
+			i--;
+		}
+	}
+	
+PT_Finish:
+	for(i = -1; i < LastLevel; i++) printf(DESIGN_close_dl);
+	
+	free(buf);
+	free(msgs);
+	wcfclose(fi);
+	wcfclose(fm);
+	return 1;
+}
+
+/* close posting messages to message thread begining from root
+ * code = 1 - CLOSE, code = 0 - OPEN
+ * return 1 if valid, 0 otherwise
+ */
+int DB_Base::DB_ChangeInvisibilityFlag(DWORD root, int invf)
+{
+	SMessage *msgs;
+	// translate virtual to real index
+	root = TranslateMsgIndex(root);
+	if(root == NO_MESSAGE_CODE) return 0;
+	msgs = (SMessage *)malloc(sizeof(SMessage)*READ_MESSAGE_HEADER+1);
+	
+	// read message
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_RW)) == NULL) printhtmlerror();
+	if(wcfseek(fm, root, SEEK_SET) == -1) printhtmlerror();
+	if(!fCheckedRead(msgs, sizeof(SMessage), fm)) printhtmlerror();
+	
+	// update flag
+	if(invf == 1)
+		msgs->Flag = msgs->Flag | MESSAGE_IS_INVISIBLE;
+	else {
+		if(msgs->Flag & MESSAGE_IS_INVISIBLE)
+			msgs->Flag = msgs->Flag - MESSAGE_IS_INVISIBLE; // should be XOR
+	}
+
+	// write message
+	if(wcfseek(fm, root, SEEK_SET) == -1) printhtmlerror();
+	if(!fCheckedWrite(msgs, sizeof(SMessage), fm)) printhtmlerror();
+	wcfclose(fm);
+	free(msgs);
+	return 1;
+}
+
+/* set collapsed flag on message root
+ * behaviour depend of code:
+ * if code == 0 - invert current value of flag
+ * if code == 1 - set collapsed flag
+ * if code == 0 - clean collapsed flag
+ * return value : 1 if flag set, or 2 if flag not set 
+ */
+int DB_Base::DB_ChangeRollMessage(DWORD root, int code)
+{
+	SMessage *msgs;
+	
+	/* translate virtual to real index */
+	root = TranslateMsgIndex(root);
+	if(root == NO_MESSAGE_CODE)
+		return 0;
+	
+	/* read message */
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_RW)) == NULL) {
+		wcfclose(fm);
+		return 0;
+	}
+
+	if(wcfseek(fm, root, SEEK_SET) != 0) {
+		wcfclose(fm);
+		return 0;
+	}
+
+	msgs = (SMessage *)malloc(sizeof(SMessage) + 1);
+
+	if(!fCheckedRead(msgs, sizeof(SMessage), fm)) {
+		wcfclose(fm);
+		free(msgs);
+		return 0;
+	}
+
+	/* update flag */
+	DWORD flg = msgs->Flag;
+	if(code == 0) {
+		if(msgs->Flag & MESSAGE_COLLAPSED_THREAD)
+			msgs->Flag = msgs->Flag & (~MESSAGE_COLLAPSED_THREAD);
+		else
+			msgs->Flag = msgs->Flag | MESSAGE_COLLAPSED_THREAD;
+	}
+	else
+	if(code == 1) {
+		msgs->Flag = msgs->Flag | MESSAGE_COLLAPSED_THREAD;
+	}
+	else
+	if(code == 2) {
+		msgs->Flag = msgs->Flag & (~MESSAGE_COLLAPSED_THREAD);
+	}
+	else {
+		/* invalid code value */
+		wcfclose(fm);
+		free(msgs);
+		return 0;
+	}
+	if(flg == msgs->Flag) {
+		wcfclose(fm);
+		free(msgs);
+		return (!(msgs->Flag & MESSAGE_COLLAPSED_THREAD)) + 1;
+	}
+
+	// write message
+	if(wcfseek(fm, root, SEEK_SET) != 0) printhtmlerror();
+	if(!fCheckedWrite(msgs, sizeof(SMessage), fm)) {
+		wcfclose(fm);
+		free(msgs);
+		return 0;
+	}
+	wcfclose(fm);
+	int res = (!(msgs->Flag & MESSAGE_COLLAPSED_THREAD)) + 1;
+	free(msgs);
+
+	return res;
+}
+
+/* set "invisible" flag for messages with Level > root.Level in (thread)
+ * code = 1 - CLOSE, code = 0 - OPEN
+ * return 1 if valid, 0 otherwise
+ */
+int DB_Base::DB_ChangeCloseThread(DWORD root, int code)
+{
+	DWORD rr;
+	DWORD *msgsel;
+	DWORD count;
+
+	/* select messages in root thread */
+	if(!SelectMessageThreadtoBuf(root, &msgsel, &count)) return 0;
+
+	/* change "invisible" flag on selected messages */
+	for(rr = 0; rr < count; rr++) {
+		DB_ChangeCloseMessage(msgsel[rr], code);
+	}
+	free(msgsel);
+
+	return 1;
+}
+
+/* change collapsed thread bit on thread tmp */
+int DB_Base::DB_ChangeRollThreadFlag(DWORD tmp)
+{
+	DWORD rr;
+	DWORD *msgsel;
+	DWORD count;
+
+	/* select messages in root thread */
+	if(!SelectMessageThreadtoBuf(tmp, &msgsel, &count)) return 0;
+
+	/* change COLLAPSED_THREAD flag on selected messages */
+	int code = 0;
+	for(rr = 0; rr < count; rr++) {
+		code = DB_ChangeRollMessage(msgsel[rr], code);
+	}
+	free(msgsel);
+
+	return 1;
+}
+
+int DB_Base::SelectMessageThreadtoBuf(DWORD root, DWORD **msgsel, DWORD *mescnt)
+{
+	SMessageTable *buf;
+	SMessage *msgs;
+	DWORD rr, fipos, toread;
+	DWORD fmpos, fl, EndLevel, viroot;
+	DWORD fisize, rd;
+	int i, j;
+	
+	// array for storing selecting messages
+	*mescnt = 0;
+	*msgsel = (DWORD*)malloc(1);
+
+	// save virtual index
+	viroot = root;
+	
+	// translate virtual to real index, and check it
+	root = TranslateMsgIndex(root);
+	if(root == NO_MESSAGE_CODE) return 0; // invalid or nonexisting index
+	
+	buf = (SMessageTable *)malloc(sizeof(SMessageTable)*READ_MESSAGE_TABLE+1);
+	msgs = (SMessage *)malloc(sizeof(SMessage)*READ_MESSAGE_HEADER+1);
+	
+	// get EndLevel (current Level of root)
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+	if(wcfseek(fm, root, SEEK_SET) == -1) printhtmlerror();
+	if(!fCheckedRead(msgs, sizeof(SMessage), fm)) printhtmlerror();
+	EndLevel = msgs->Level;
+	wcfclose(fm);
+	
+	if((fi = wcfopen(F_INDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+	if(wcfseek(fi, 0, SEEK_END) == -1) printhtmlerror();
+	
+	// temporary !!! should be added index support
+	// find index in index file
+	fisize = fl = wcftell(fi);
+	
+	buf = (SMessageTable *)malloc(sizeof(SMessageTable)*READ_MESSAGE_TABLE + 1);
+	
+	while(fl > 0) {
+		DWORD toread;
+		if(fl >= READ_MESSAGE_TABLE*sizeof(SMessageTable)) {
+			fl = fl - READ_MESSAGE_TABLE*sizeof(SMessageTable);
+			toread = READ_MESSAGE_TABLE*sizeof(SMessageTable);
+		}
+		else {
+			toread = fl;
+			fl = 0;
+		}
+		if(wcfseek(fi, fl, SEEK_SET) == -1) printhtmlerror();
+		if(!fCheckedRead(buf, toread, fi)) printhtmlerror();
+		rd = i = (toread + 1) / sizeof(SMessageTable) - 1;
+		while(i>=0) {
+			if(M_IN(root, buf[i].begin, buf[i].end) || M_IN(root, buf[i].end, buf[i].begin)) {
+				goto PT_Found;
+			}
+			i--;
+		}
+	}
+	
+	// not found in indexes - fatal error
+	return 0;
+	
+PT_Found:
+	
+	fl = fl + (i + 1)*sizeof(SMessageTable);
+	
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+	if(wcfseek(fi, fl, SEEK_SET) == -1) printhtmlerror();
+	
+	fipos = wcftell(fi);
+	
+	//int czero = 0;
+	// flag, showing if we reach ViIndex of root msg
+	int reachviroot = 0;
+	
+	for(;;) {
+		if(fipos == 0) break;
+		else {
+			if(fipos >= READ_MESSAGE_TABLE*sizeof(SMessageTable)) {
+				toread = READ_MESSAGE_TABLE*sizeof(SMessageTable);
+				fipos = fipos - READ_MESSAGE_TABLE*sizeof(SMessageTable);
+			}
+			else {
+				toread = fipos;
+				fipos = 0;
+			}
+		}
+		if(wcfseek(fi, fipos, SEEK_SET) == -1) printhtmlerror();
+		if((rr = wcfread(buf, 1, toread, fi)) % sizeof(SMessageTable) != 0) printhtmlerror();
+		signed long i = rr / sizeof(SMessageTable) - 1;
+		while(i >= 0) {
+			
+			if(buf[i].begin < buf[i].end ) {
+				// forward direction
+				fmpos = buf[i].begin;
+				/*if(!czero) {
+				czero = 1;
+				fmpos = root;
+			}*/
+				if(wcfseek(fm, fmpos, SEEK_SET) == -1) printhtmlerror();
+				while(fmpos != (buf[i].end + 1)) {
+					DWORD toread;
+					if(buf[i].end - fmpos < READ_MESSAGE_HEADER*sizeof(SMessage)) {
+						toread = buf[i].end - fmpos + 1;
+						fmpos = fmpos + toread;
+					}
+					else {
+						toread = READ_MESSAGE_HEADER*sizeof(SMessage);
+						fmpos = fmpos + toread;
+					}
+					if(!fCheckedRead(msgs, toread, fm)) printhtmlerror();
+					rr = (toread + 1)/ sizeof(SMessage);
+					
+					for(j = 0; j < rr; j++) {
+						if(viroot == msgs[j].ViIndex) {
+							reachviroot = 1;
+						}
+						if(msgs[j].Level <= EndLevel && viroot != msgs[j].ViIndex && reachviroot) {
+							goto PT_Finish;
+						}
+						if(reachviroot) {
+							(*mescnt)++;
+							(*msgsel) = (DWORD*)realloc((*msgsel), (*mescnt)*sizeof(DWORD));
+							(*msgsel)[(*mescnt) - 1] = msgs[j].ViIndex;
+						}
+					}
+				}
+			}
+			else {
+				// backward direction
+				DWORD toread;
+				fmpos = buf[i].begin + 1;
+				/*if(!czero) {
+				czero = 1;
+				fmpos = root;
+			}*/
+				while(fmpos != buf[i].end) {
+					if( fmpos - buf[i].end > READ_MESSAGE_HEADER*sizeof(SMessage)) {
+						fmpos = fmpos - READ_MESSAGE_HEADER*sizeof(SMessage);
+						toread = READ_MESSAGE_HEADER*sizeof(SMessage);
+					}
+					else {
+						toread = fmpos - buf[i].end;
+						fmpos = buf[i].end;
+					}
+					
+					if(wcfseek(fm, fmpos, SEEK_SET) == -1) printhtmlerror();
+					if(!fCheckedRead(msgs, toread, fm)) printhtmlerror();
+					rr = (toread + 1)/ sizeof(SMessage) - 1;
+					
+					for(j=rr; j >= 0; j--) {
+						if(viroot == msgs[j].ViIndex) {
+							reachviroot = 1;
+						}
+						if(msgs[j].Level <= EndLevel && viroot != msgs[j].ViIndex && reachviroot) {
+							goto PT_Finish;
+						}
+						if(reachviroot) {
+							(*mescnt)++;
+							(*msgsel) = (DWORD*)realloc((*msgsel), (*mescnt)*sizeof(DWORD));
+							(*msgsel)[(*mescnt) - 1] = msgs[j].ViIndex;
+						}
+					}
+				}
+			}
+			i--;
+		}
+	}
+PT_Finish:
+	wcfclose(fi);
+	wcfclose(fm);
+	free(buf);
+	free(msgs);
+	return 1;
+}
+
+// change "closed" flag on root message
+// return 1 if successfull, otherwise 0
+int DB_Base::DB_ChangeCloseMessage(DWORD root, int code)
+{
+	SMessage *msgs;
+	// translate virtual to real index
+	root = TranslateMsgIndex(root);
+	
+	msgs = (SMessage *)malloc(sizeof(SMessage)*READ_MESSAGE_HEADER+1);
+	
+	// read message
+	if((fm = wcfopen(F_MSGINDEX, FILE_ACCESS_MODES_RW)) == NULL) 
+		printhtmlerror();
+	// ******* lock FM *******
+	lock_file(fm);
+
+	if(wcfseek(fm, root, SEEK_SET) == -1) {
+		unlock_file(fm);
+		printhtmlerror();
+	}
+	if(!fCheckedRead(msgs, sizeof(SMessage), fm)) {
+		unlock_file(fm);
+		printhtmlerror();
+	}
+	// update flag
+	if(!code) {
+		if(msgs->Flag & MESSAGE_IS_CLOSED)
+			msgs->Flag = msgs->Flag - MESSAGE_IS_CLOSED;
+	}
+	else msgs->Flag = msgs->Flag | MESSAGE_IS_CLOSED;
+	// write message
+	if(wcfseek(fm, root, SEEK_SET) == -1) printhtmlerror();
+	if(!fCheckedWrite(msgs, sizeof(SMessage), fm)) {
+		unlock_file(fm);
+		printhtmlerror();
+	}
+
+	unlock_file(fm);
+	// ******* unlock FM *******
+
+	wcfclose(fm);
+	free(msgs);
+	return 1;
+}
+
+// change "invisible" flag on all messages with Level > root.Level
+// return 1 if successfull, otherwise 0
+int DB_Base::DB_ChangeInvisibilityThreadFlag(DWORD root, int invf)
+{
+	DWORD rr;
+	DWORD *msgsel;
+	DWORD count;
+	// select messages in root thread
+	if(!SelectMessageThreadtoBuf(root, &msgsel, &count)) return 0;
+	//change "invisible" flag on selected messages
+	for(rr = 0; rr < count; rr++) {
+		DB_ChangeInvisibilityFlag(msgsel[rr], invf);
+	}
+	free(msgsel);
+
+	return 1;
+}
+
+// return translated code, or NO_MESSAGE_CODE
+DWORD DB_Base::TranslateMsgIndex(DWORD root)
+{
+	DWORD r;
+	if(root !=0) {
+		if((fv = wcfopen(F_VINDEX, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+		if(!(wcfseek(fv, root*sizeof(DWORD), SEEK_SET) != 0)) {
+			if(!fCheckedRead(&r, sizeof(DWORD), fv)) {
+				// reach end of file ?
+				r = NO_MESSAGE_CODE;
+			}
+		}
+		else r = NO_MESSAGE_CODE;
+		wcfclose(fv);
+	}
+	else r = NO_MESSAGE_CODE;
+	return r;
+}
+
+/* add message with real index root to virtual indexes and return
+   virtual index of this message */
+DWORD DB_Base::AddMsgIndex(DWORD root)
+{
+	DWORD r;
+	// test if it's valid value
+	//if(root == NO_MESSAGE_CODE) printhtmlerror();
+	
+	if((fv = wcfopen(F_VINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+		printhtmlerror();
+	// ******* lock FV *******
+	lock_file(fv);
+
+	if(wcfseek(fv, 0, SEEK_END) < 0) {
+		unlock_file(fv);
+		printhtmlerror();
+	}
+	r = wcftell(fv);
+	// in case if file is empty, to avoid msg_id=0
+	if (r == 0){
+		if(!fCheckedWrite(&r, sizeof(DWORD), fv)) {
+			unlock_file(fv);
+			printhtmlerror();
+		}
+		r = wcftell(fv);
+	}
+
+	if(!fCheckedWrite(&root, sizeof(DWORD), fv)) {
+		unlock_file(fv);
+		printhtmlerror();
+	}
+	r = (r+1)/sizeof(DWORD);
+
+	unlock_file(fv);
+	// ******* unlock FV *******
+
+	wcfclose(fv);
+	return r;
+}
+
+// delete virtual message index
+// return 1 if successfull, 0 otherwise
+int DB_Base::DeleteMsgIndex(DWORD root)
+{
+	
+	if((fv = wcfopen(F_VINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+		return 0;
+	// ******* lock FV *******
+	lock_file(fv);
+
+	if(wcfseek(fv, root*sizeof(DWORD), SEEK_SET) < 0) {
+		unlock_file(fv);
+		return 0;
+	}
+	root = NO_MESSAGE_CODE;
+	if(!fCheckedWrite(&root, sizeof(DWORD), fv)) {
+		unlock_file(fv);
+		return 0;
+	}
+	unlock_file(fv);
+	// ******* unlock FV *******
+
+	wcfclose(fv);
+	return 1;
+}
+
+DWORD DB_Base::VIndexCountInDB()
+{	
+	DWORD fsize;
+	fsize = Fsize(F_VINDEX);
+	if (fsize > 0)
+		return ( (DWORD)(((DWORD)fsize) - 3) )/sizeof(DWORD);
+	else 
+		return 0;
+
+}
+
+DWORD DB_Base::MessageCountInDB()
+{
+	return ( ( (DWORD)(((DWORD)Fsize(F_MSGINDEX))) )/sizeof(SMessage) );
+}
+
+int DB_Base::ReadMainThreadCount(DWORD *root)
+{
+	FILE *f;
+	int ret = 0;
+	if((f = fopen(F_VINDEX, FILE_ACCESS_MODES_R)) == NULL)
+		return ret;
+	if(fread(root, 1, sizeof(DWORD), f) == sizeof(DWORD)) {
+		ret = 1;
+	}
+	fclose(f);
+
+	return ret;
+}
+
+int DB_Base::IncrementMainThreadCount()
+{
+	DWORD root;
+	if((fv = wcfopen(F_VINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+		return 0;
+	// ******* lock FV *******
+	lock_file(fv);
+
+	if(!fCheckedRead(&root, sizeof(DWORD), fv)) {
+		unlock_file(fv);
+		return 0;
+	}
+	if(wcfseek(fv, 0, SEEK_SET) < 0) {
+		unlock_file(fv);
+		return 0;
+	}
+	root++;
+	if(!fCheckedWrite(&root, sizeof(DWORD), fv)) {
+		unlock_file(fv);
+		return 0;
+	}
+	unlock_file(fv);
+	// ******* unlock FV *******
+
+	wcfclose(fv);
+
+	return 1;
+}
+
+int DB_Base::DecrementMainThreadCount()
+{
+	DWORD root;
+	if((fv = wcfopen(F_VINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+		return 0;
+	// ******* lock FV *******
+	lock_file(fv);
+
+	if(!fCheckedRead(&root, sizeof(DWORD), fv)) {
+		unlock_file(fv);
+		return 0;
+	}
+	if(wcfseek(fv, 0, SEEK_SET) < 0) {
+		unlock_file(fv);
+		return 0;
+	}
+	if(root) root--;
+	if(!fCheckedWrite(&root, sizeof(DWORD), fv)) {
+		unlock_file(fv);
+		return 0;
+	}
+	unlock_file(fv);
+	// ******* unlock FV *******
+
+	wcfclose(fv);
+
+	return 1;
+}
+
+#ifdef WIN32
+
+DWORD Fsize(char *s)
+{
+	HANDLE hFile = CreateFile(s, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 
+		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+	DWORD sizeHigh, sizeLow;
+	if(hFile == INVALID_HANDLE_VALUE) 
+	{
+		if(GetLastError() == ERROR_SHARING_VIOLATION)
+		{
+			WIN32_FIND_DATA wfd;
+			HANDLE hSearch = FindFirstFile(s, &wfd);
+			if(hSearch != INVALID_HANDLE_VALUE)
+			{				
+				FindClose(hSearch);
+				sizeLow = wfd.nFileSizeLow;
+				sizeHigh = wfd.nFileSizeHigh;
+				goto ret_size;
+			}
+		}
+		else {
+			char ss[10000];
+			sprintf(ss, LOG_GETFILESIZEFAILED, s);
+			printhtmlerrormes(ss);
+		}
+	}
+	sizeLow = GetFileSize(hFile, &sizeHigh);
+	CloseHandle(hFile);
+ret_size:
+	if(sizeHigh) {
+		char ss[10000];
+		sprintf(ss, LOG_FILESIZETOOHIGH, s);
+		printhtmlerrormes(ss);
+	}
+	return sizeLow;
+}
+
+#else //WIN32
+
+DWORD Fsize(char *s)
+{
+	WCFILE *f;
+	register DWORD r;
+	if((f = wcfopen(s, FILE_ACCESS_MODES_R)) == NULL) {
+			char ss[10000];
+			sprintf(ss, LOG_GETFILESIZEFAILED, s);
+			printhtmlerrormes(ss);
+	}
+	if(wcfseek(f, 0, SEEK_END) != 0) {
+			char ss[10000];
+			sprintf(ss, LOG_GETFILESIZEFAILED, s);
+			printhtmlerrormes(ss);
+	}
+	r = wcftell(f);
+	wcfclose(f);
+	return r;
+}
+
+#endif //WIN32
blob - /dev/null
blob + 7f4a64dbb7ad065b78eb36e977bc1ee24372889e (mode 644)
--- /dev/null
+++ src/dbase.h
@@ -0,0 +1,152 @@
+/***************************************************************************
+                      dbase.h  -  message database engine include
+                         -------------------
+    begin                : Wed Mar 14 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef DBASE_H_INCLUDED
+#define DBASE_H_INCLUDED
+
+#include "basetypes.h"
+#include "speller.h"
+#include "logins.h"
+#include "colornick.h"
+
+struct SMessageTable
+{
+	/* index ordering table */
+	DWORD begin;
+	DWORD end;
+};
+
+#define PRINTMODE_NULL			0x0000
+#define PRINTMODE_ALL_ROLLED	0x0001
+
+// IP address of user
+extern char *Cip;
+extern DWORD Nip;
+
+
+/* cookie data */
+extern time_t	RefreshDate;
+extern int		currentlsel;
+extern int		currenttc;
+extern int		currenttt;
+extern int		currenttv;
+extern int		currentss;
+extern int		currentdsm;
+extern DWORD	currenttopics;
+extern int		currentlann;
+extern int		topicsoverride;
+extern int		currentlm;	// last message
+extern int		currentfm;	// first message
+extern int		currentlt;	// last threads
+extern int		currentft;	// first threads
+extern int		currenttz;	
+
+extern int cookie_lsel;
+extern int cookie_tc;
+extern int cookie_tt;
+extern int cookie_tv;
+extern int cookie_ss;
+extern int cookie_dsm;
+extern DWORD cookie_topics;
+extern int cookie_tz;
+
+extern DWORD cookie_lastenter;
+extern char *cookie_seq;
+extern char *cookie_name;
+
+extern time_t current_minprntime;
+
+/* shows if header of CGI script was printed */
+extern int HPrinted;
+
+extern CUserLogin ULogin;
+
+#if USER_ALT_NICK_SPELLING_SUPPORT
+extern CAltNamesParser AltNames;
+#endif
+
+/* ------------------------
+ *  functions
+ * ------------------------
+ */
+DWORD Fsize(char *s);
+int ConvertTime(time_t tt, char *s);
+char *ConvertFullTime(time_t tt);
+int ReadDBMessage(DWORD midx, SMessage *mes);
+int ReadDBMessageBody(char *buf, DWORD index, int size);
+int WriteDBMessage(DWORD midx, SMessage *mes);
+int IP2HostName(DWORD IP, char *hostname, int maxlen);
+
+class DB_Base
+{
+protected:
+	WCFILE	*fi,	// random access index file
+			*fm,	// message headers
+			*fb,	// message bodies
+			*fv,	// virtual index file
+			*ffm,	// free spaces in message headers
+			*ffb;	// free spaces in message bodies
+
+	int alrprn;		// count of already printed threads
+	int nt_counter;	// count of printed new threads
+	int nm_counter;	// count of printed new msgs
+	/* fpr printhtmlindex */
+	int invflag;	// "invisible thread was printed" flag
+	int collapsed;	// "rolled thread was printed" flags
+	int newmessflag;// "new message" mark preparing for collapsed threads
+	SMessage pmes;	// for message preprinting
+	SMessage lastmes;	// for last posted message in collapsed thread
+
+	int SelectMessageThreadtoBuf(DWORD root, DWORD **msgsel, DWORD *msgcnt);
+	
+	int printhtmlbuffer(SMessage *buf, DWORD size, int p, int *ll, int *pr, DWORD mode, DWORD &shouldprint, DWORD &skipped);
+	int printThreadbuffer(SMessage *buf, DWORD size, int p, DWORD fmpos, int ll, int *czero, DWORD selected, DWORD root, int *bp);
+	int printhtmlindexhron_bythreads(DWORD mode);
+	int printhtmlindexhron_wothreads();
+	int DB_Base::printhtmlmessage_in_index(SMessage *mes, int style, DWORD skipped = 0xffffffff, int newmessmark = 0);
+
+	int DB_ChangeInvisibilityFlag(DWORD root, int invf);
+	int DB_ChangeCloseMessage(DWORD root, int code);
+	int DB_DeleteMessage(DWORD root);
+	int DB_ChangeRollMessage(DWORD root, int code);
+
+public:
+	DB_Base();
+	~DB_Base();
+	
+	DWORD TranslateMsgIndex(DWORD root);
+	DWORD AddMsgIndex(DWORD root);
+	int DeleteMsgIndex(DWORD root);
+	DWORD VIndexCountInDB();
+
+	DWORD MessageCountInDB();
+
+	int IncrementMainThreadCount();
+	int DecrementMainThreadCount();
+	int ReadMainThreadCount(DWORD *root);
+	
+	int PrintHtmlMessageBody(SMessage *mes,  char *body);
+	int PrintHtmlMessageBufferByVI(DWORD *VI, DWORD cnt);
+
+	int DB_InsertMessage(struct SMessage *mes, DWORD root, WORD msize, char** body, DWORD CFlags, char *passw, char **banreason);
+	int DB_ChangeMessage(DWORD root, SMessage *msg, char **body, WORD msize, DWORD CFlags, char **banreason);
+
+	int PrintandCheckMessageFavsExistandInv(SProfile_UserInfo *ui, DWORD viewinv, int *updated);
+	
+	int DB_DeleteMessages(DWORD root);
+	int DB_ChangeInvisibilityThreadFlag(DWORD root, int invf);
+	int DB_ChangeRollThreadFlag(DWORD tmp);
+	int DB_ChangeCloseThread(DWORD root, int code);
+	int DB_PrintMessageThread(DWORD root);
+	int DB_PrintHtmlIndex(time_t time1, time_t time2, DWORD mtc);
+	int DB_PrintMessageBody(DWORD root);
+	void Profile_UserName(char *name, char *tostr, int reg, int doparsehtml = 1);
+};
+
+#endif
+
blob - /dev/null
blob + 5221175e0f0f078012744624f9b8869090ca6fa0 (mode 644)
--- /dev/null
+++ src/error.cpp
@@ -0,0 +1,156 @@
+/***************************************************************************
+                          error.cpp  -  log&error handler
+                             -------------------
+    begin                : Wed Mar 14 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "stdarg.h"
+#include "dbase.h"
+#include "error.h"
+#include "messages.h"
+
+/* print message to logfile
+ * s - format string
+ *		%s		string
+ *		%d[f]	DWORD (if 'f' as hex)
+ *		%b[f]	BYTE (if 'f' as hex)
+ */
+void print2log(char *s, ...)
+{
+	DWORD i = 0, c = 0;
+	FILE *f;
+	//
+	// POTENTIAL BUG HERE
+	//
+	char xx[100];
+	char *ss = (char*)malloc(100*strlen(s));
+	ss[0] = 0;
+	va_list marker;
+	
+/*	if((f = fopen(LOG_FILE, "a")) != NULL) {
+		fprintf(f, "entering:");
+		fclose(f);
+	}*/
+
+	// Initialize variable arguments
+	va_start(marker, s);
+	DWORD slen = strlen(s);
+	while(i < slen)
+	{
+		if(s[i] == '%') {
+			if(i + 1 < slen) {
+				i++;
+				switch(s[i]) {
+					case 'd':
+						{
+							bool fhex = false;
+							if(i + 1 < slen && s[i+1] == 'f')
+							{
+								fhex = true;
+								i++;
+							}
+							DWORD x = va_arg(marker, DWORD);
+							if(!fhex) sprintf(xx,"%lu", x);
+							else {
+								sprintf(xx,"%lx", x);
+								strcat(ss, "0x");
+							}
+							strcat(ss, xx);
+							break;
+						}
+					case 's':
+						{
+							char *x = va_arg(marker, char*);
+							if(x) strcat(ss, x);
+							else strcat(ss, "null");
+							break;
+						}
+					case 'b':
+						{
+							bool fhex = false;
+							if(i + 1 < slen && s[i+1] == 'f')
+							{
+								fhex = true;
+								i++;
+							}
+							BYTE x = (BYTE)va_arg(marker, int);
+							if(!fhex) sprintf(xx,"%hu", x);
+							else {
+								sprintf(xx,"%hx", x);
+								strcat(ss, "0x");
+							}
+							strcat(ss, xx);
+							break;
+						}
+					default:
+						{
+							char tmp[3];
+							tmp[0] = s[i-1];
+							tmp[1] = s[i];
+							tmp[2] = 0;
+							strcat(ss, tmp);
+						}
+				}
+				c = strlen(ss);
+			}
+			else {
+				ss[c] = s[i];
+				c++;
+				ss[c] = 0;
+			}
+
+		}
+		else {
+			ss[c] = s[i];
+			c++;
+			ss[c] = 0;
+		}
+		i++;
+	}
+	// Reset variable arguments
+	va_end(marker);
+
+	time_t t;
+	char *p;
+	if((f = fopen(LOG_FILE, "a")) != NULL) {
+		t = time(NULL);
+		p = ctime(&t);
+		p[strlen(p) - 1] = 0;
+		fprintf(f, "%s : %s\n", p, ss);
+		fclose(f);
+	}
+	free(ss);
+}
+
+
+/* print error to file [file] at line [line] and message then immediately exit */
+int printwidehtmlerror(char *file, DWORD line, char *s)
+{
+#if ENABLE_LOG
+	print2log(LOG_UNHANDLED, file, line, getenv(REMOTE_ADDR),
+		(s && (*s != 0)) ? s : LOG_ERRORTYPEUNKN, getenv(QUERY_STRING));
+#endif
+	// for correct showing in browser
+	if(!HPrinted) printf("Content-type: text/html\n\n<HTML><HEAD><TITLE>" \
+		TITLE_WWWConfBegining TITLE_divider "Error during page refresh</TITLE></HEAD>");
+
+	printf("<p><B><H3>An error occured</H3></B></p><p>Try to refresh this page, and if"
+	" this occure again please contact server <a href=\"mailto:%s\">"
+	" administrator </a> for support", ADMIN_MAIL);
+#if ERROR_ON_SCREEN == 0
+#if ENABLE_LOG
+	printf("<p><font color=#ff0000> This error have been logged to the"
+	" server log");
+#endif
+#else
+	printf("<P><font color=#ff0000><I>Technical details</I></font><BR>" \
+		"<font color=#0000ff>" LOG_UNHANDLED_HTML, file, line, getenv(REMOTE_ADDR),
+		(s && (*s != 0)) ? s : LOG_ERRORTYPEUNKN, getenv(QUERY_STRING));
+#endif
+	printf("</HTML>");
+	fflush(stdout);
+	exit(0);
+}
blob - /dev/null
blob + 4cdc6fb05cb47fdd1f028c6152dd448afcd8feda (mode 644)
--- /dev/null
+++ src/error.h
@@ -0,0 +1,22 @@
+/***************************************************************************
+                          error.h  -  log&error handler header
+                             -------------------
+    begin                : Wed Mar 14 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef ERROR_H_INCLUDED
+#define ERROR_H_INCLUDED
+
+#define printhtmlerror() printwidehtmlerror(__FILE__, __LINE__, "")
+#define printhtmlerrormes(s) printwidehtmlerror(__FILE__, __LINE__, s)
+#define printhtmlerrorat(p, s) { \
+	char ss[10000]; \
+	sprintf(ss, p, s); \
+	printwidehtmlerror(__FILE__, __LINE__, ss); }
+
+void print2log(char *s, ...);
+int printwidehtmlerror(char *file, DWORD line, char *s);
+
+#endif
blob - /dev/null
blob + bc6c5813ed7f281c9b5e3d9b5906bc7a7c60b0a9 (mode 644)
--- /dev/null
+++ src/freedb.cpp
@@ -0,0 +1,181 @@
+/***************************************************************************
+                          freedb.cpp  -  free spaces database support
+                             -------------------
+    begin                : Sun Apr 29 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "freedb.h"
+
+#define unlock_and_freedb_io_error1() {unlock_file(ffb);errnum = FREEDBFILE_ERROR_IO_ERROR;return FREEDBFILE_ERROR_IO_ERROR;}
+#define freedb_io_error1() {errnum = FREEDBFILE_ERROR_IO_ERROR; return FREEDBFILE_ERROR_IO_ERROR;}
+#define freedb_lock_file() {lock_file(ffb);}
+#define freedb_unlock_file() {unlock_file(ffb)}
+
+
+/* mark free space block with size bsize and index bIndex
+ * if successfull return FREEDB_ERROR_ALLOK
+ */
+DWORD CFreeDBFile::MarkFreeSpace(DWORD bIndex, DWORD bsize)
+{
+	SFreeDBEntry fs;
+	DWORD rr;
+	WCFILE *ffb;
+
+	if(!init) {
+		errnum = FREEDBFILE_ERROR_NOT_INITIALIZED;
+		return errnum;
+	}
+
+	// ignore wasted blocks
+	if(bsize < wasted_block) bsize = 0;
+
+	if((ffb = wcfopen(fname, FILE_ACCESS_MODES_RW)) == NULL) {
+		if((ffb = wcfopen(fname, FILE_ACCESS_MODES_CW)) == NULL) {
+			freedb_io_error1()
+		}
+		else {
+			wcfclose(ffb);
+			if((ffb = wcfopen(fname, FILE_ACCESS_MODES_RW)) == NULL) {
+				freedb_io_error1()
+			}
+		}
+	}
+	/* seek at begining of WCFILE */
+	if(wcfseek(ffb, 0, SEEK_SET) != 0) {
+		freedb_io_error1();
+	}
+
+	/********* lock WCFILE *********/
+	freedb_lock_file();
+
+	int alreadyfind = 0;
+	while(!wcfeof(ffb)) {
+		if((rr = (DWORD)wcfread(&fs, 1, sizeof(SFreeDBEntry), ffb)) != sizeof(SFreeDBEntry)) {
+			if(rr == 0) break;
+			unlock_and_freedb_io_error1();
+		}
+		if(fs.size == 0) {
+			alreadyfind = 1;
+			rr = wcftell(ffb) - sizeof(SFreeDBEntry);
+			if(wcfseek(ffb, rr, SEEK_SET) != 0) {
+				unlock_and_freedb_io_error1();
+			}
+			fs.size = bsize;
+			fs.index = bIndex;
+			if(!fCheckedWrite(&fs, sizeof(SFreeDBEntry), ffb)) {
+				unlock_and_freedb_io_error1();
+			}
+			break;
+		}
+	}
+	if(!alreadyfind) {
+		if(wcfseek(ffb, 0, SEEK_END) != 0) {
+			unlock_and_freedb_io_error1()
+		}
+		fs.size = bsize;
+		fs.index = bIndex;
+		if(!fCheckedWrite(&fs, sizeof(SFreeDBEntry), ffb)) {
+			unlock_and_freedb_io_error1()
+		}
+	}
+	freedb_unlock_file();
+	/******* unlock ffb WCFILE *******/
+	wcfclose(ffb);
+	errnum = FREEDBFILE_ERROR_ALLOK;
+	return FREEDBFILE_ERROR_ALLOK;
+}
+
+/* allocate size bytes of free space, and return index of it
+ * otherwise return 0xFFFFFFFF and set errnum with error code
+ */
+DWORD CFreeDBFile::AllocFreeSpace(DWORD size)
+{
+	SFreeDBEntry fs;
+	DWORD rr;
+	WCFILE *ffb;
+	
+	if(!init) {
+		errnum = FREEDBFILE_ERROR_NOT_INITIALIZED;
+		return 0xFFFFFFFF;
+	}
+
+	if((ffb = wcfopen(fname, FILE_ACCESS_MODES_RW)) == NULL) {
+		if((ffb = wcfopen(fname, FILE_ACCESS_MODES_CW)) == NULL) {
+			freedb_io_error1()
+		}
+		else {
+			wcfclose(ffb);
+			if((ffb = wcfopen(fname, FILE_ACCESS_MODES_RW)) == NULL) {
+				freedb_io_error1()
+			}
+		}
+	}
+	/* seek at begining of WCFILE */
+	if(wcfseek(ffb, 0, SEEK_SET) != 0) {
+		freedb_io_error1();
+	}
+
+	/******** lock ffb *********/
+	freedb_lock_file();
+
+	while(!wcfeof(ffb)) {
+		if((rr = (DWORD)wcfread(&fs, 1, sizeof(SFreeDBEntry), ffb)) != sizeof(SFreeDBEntry)) {
+			if(rr == 0) {
+				break;
+			}
+			unlock_and_freedb_io_error1();
+		}
+		if(fs.size >= size) {
+			rr = wcftell(ffb) - sizeof(SFreeDBEntry);
+			if(wcfseek(ffb, rr, SEEK_SET) != 0) {
+				unlock_and_freedb_io_error1()
+			}
+
+			fs.size = fs.size - size;
+			fs.index = fs.index + size;
+
+			// make wasted space, if block too small
+			if(fs.size < wasted_block) fs.size = 0;
+			
+			if(!fCheckedWrite(&fs, sizeof(SFreeDBEntry), ffb)) {
+				unlock_and_freedb_io_error1()
+			}
+			
+			freedb_unlock_file();
+			wcfclose(ffb);
+			// unlock FFB semaphore
+			return fs.index - size;
+		}
+	}
+
+	freedb_unlock_file();
+	/********* unlock ffb *********/
+
+	wcfclose(ffb);
+
+	return 0xFFFFFFFF;
+}
+
+CFreeDBFile::CFreeDBFile(char *ifname, DWORD wasted_b)
+{
+	init = 0;
+	if(ifname == NULL || strlen(ifname) < 1) {
+		errnum = FREEDBFILE_ERROR_INVALID_FILE;
+		return;
+	}
+	fname = (char*)malloc(strlen(ifname) + 1);
+	strcpy(fname, ifname);
+	wasted_block = wasted_b;
+	errnum = FREEDBFILE_ERROR_ALLOK;
+	init = 1;
+}
+
+CFreeDBFile::~CFreeDBFile()
+{
+	if(init) {
+		free(fname);
+	}
+}
blob - /dev/null
blob + 23b6a1da4ab63dd0d60ef44e247ff4e6ab94322d (mode 644)
--- /dev/null
+++ src/freedb.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+                          freedb.h  -  free spaces database support include
+                             -------------------
+    begin                : Sun Apr 29 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef FREEDBFILE_H_INCLUDED
+#define FREEDBFILE_H_INCLUDED
+
+#include "basetypes.h"
+
+#define FREEDBFILE_ERROR_ALLOK					0
+#define FREEDBFILE_ERROR_NOT_INITIALIZED		1
+#define FREEDBFILE_ERROR_IO_ERROR				2
+#define FREEDBFILE_ERROR_INVALID_FILE			3
+
+#define FREEDBFILE_NO_FREE_SPACE		0xFFFFFFFF
+
+#define FREEDBFILE_READBUF_COUNT				20
+
+/* free spaces index table entry */
+struct SFreeDBEntry {
+	DWORD size;
+	DWORD index;
+};
+
+class CFreeDBFile {
+protected:
+	char *fname;
+	int init;
+	DWORD wasted_block;
+public:
+	CFreeDBFile(char *ifname, DWORD wasted_block);
+	~CFreeDBFile();
+	DWORD errnum;
+	DWORD MarkFreeSpace(DWORD bIndex, DWORD bsize);
+	DWORD AllocFreeSpace(DWORD size);
+};
+
+#endif
blob - /dev/null
blob + 70ab2c6a87617860d924be22f2160005b51014a7 (mode 644)
--- /dev/null
+++ src/hashindex.cpp
@@ -0,0 +1,500 @@
+/***************************************************************************
+                          hashindex.cpp  -  hashed indexes for strings
+                             -------------------
+    begin                : Sun Nov 5 2002
+    copyright            : (C) 2001-2002 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "hashindex.h"
+
+#define hi_lock_file()		{lock_file(f);}
+#define hi_unlock_file()	{unlock_file(f);}
+
+#define OFILE_NAME F_PROF_INDEX
+
+/*				Index WCFILE format
+ *	db 10, [name], 13, [Index=DWORD 4 bytes]
+ *  ........................................
+ */
+
+static char* mstrstr(char *s, char *f, DWORD size)
+{
+	char *ss, *ff = f;
+	DWORD i = 0;
+	while(i <= size) {
+		ss = s;
+		ff = f;
+		while(*s == *ff && *ff != 0) {
+			s++;
+			i++;
+			ff++;
+		}
+		if(*ff == 0) {
+			return ss;
+		}
+		if(s - ss == 0) {
+			s++;
+			i++;
+		}
+	}
+	return NULL;
+}
+
+DWORD hashstr(char *s, DWORD m)
+{
+	DWORD sum = 0;
+	for(; *s != 0; s++) {
+		sum = sum + (*s);
+	}
+	return (sum % m);
+}
+
+int GetIndexOfString(char *s, DWORD *Index)
+{
+	WCFILE *f;
+	DWORD hash;
+	char buf[HASHINDEX_BLOCK_SIZE];
+	char ps[MAX_HASHINDEX_STRLEN + 10];
+	HASHINDEX_BLOCKINFO bi;
+	char *fs;
+
+	if(strlen(s) < 3 || strlen(s) > MAX_HASHINDEX_STRLEN)
+		return HASHINDEX_ER_FORMAT;
+
+	hash = HASHINDEX_BLOCK_SIZE * hashstr(s, HASHTAB_LEN);
+
+	if((f = wcfopen(OFILE_NAME, FILE_ACCESS_MODES_RW)) == NULL)
+		return HASHINDEX_ER_IO_READ;
+
+	for(;;) {
+		if(wcfseek(f, hash, SEEK_SET) != 0) {
+			hi_unlock_file();
+			return HASHINDEX_ER_IO_READ;
+		}
+		
+		if(!fCheckedRead(buf, HASHINDEX_BLOCK_SIZE, f)) {
+			hi_unlock_file();
+			return HASHINDEX_ER_IO_READ;
+		}
+
+		ps[0] = 10;
+		strcpy(&ps[1], s);
+		ps[strlen(s) + 1] = 13;
+		ps[strlen(s) + 2] = 0;
+		memcpy(&bi, buf, sizeof(bi));
+
+		//
+		//	Search for string in loaded block
+		//
+		if((fs = mstrstr(buf + sizeof(HASHINDEX_BLOCKINFO), ps, bi.Used)) != NULL) {
+			memcpy(Index, fs + strlen(s) + 2, 4);
+			break;
+		}
+
+		if(bi.Next == HASHINDEX_NULL) {
+			wcfclose(f);
+			return HASHINDEX_ER_NOT_FOUND;
+		}
+		else hash = bi.Next;
+	}
+
+	wcfclose(f);
+
+	return HASHINDEX_ER_OK;
+}
+
+int AddStringToHashedIndex(char *s, DWORD Index)
+{
+	WCFILE *f;
+	DWORD oldhash, hash, neededsize, i;
+	HASHINDEX_BLOCKINFO bi;
+	char buf[HASHINDEX_BLOCK_SIZE];
+	char prepbuf[MAX_HASHINDEX_STRLEN + 10];
+
+	if(strlen(s) < 3 || strlen(s) > MAX_HASHINDEX_STRLEN)
+		return HASHINDEX_ER_FORMAT;
+
+	hash = HASHINDEX_BLOCK_SIZE * hashstr(s, HASHTAB_LEN);
+	
+	if((f = wcfopen(OFILE_NAME, FILE_ACCESS_MODES_RW)) == NULL) {
+		//
+		//	try to create new index WCFILE
+		//
+		if((f = wcfopen(OFILE_NAME, FILE_ACCESS_MODES_CW)) == NULL)
+			return HASHINDEX_ER_IO_CREATE;
+
+		hi_lock_file();
+
+		memset(buf, 0, HASHINDEX_BLOCK_SIZE);
+		bi.Used = sizeof(HASHINDEX_BLOCKINFO);
+		bi.Next = HASHINDEX_NULL;
+		memcpy(buf, &bi, sizeof(bi));
+
+		for(i = 0; i < HASHTAB_LEN; i++) {
+			if(!fCheckedWrite(buf, HASHINDEX_BLOCK_SIZE, f)) {
+				hi_unlock_file();
+				wcfclose(f);
+				return HASHINDEX_ER_IO_WRITE;
+			}
+		}
+
+		hi_unlock_file();
+	}
+	//
+	//	Lock index WCFILE
+	//
+	hi_lock_file();
+
+	neededsize = strlen(s) + 4 /* for Index*/  + 2 /* for 10 and 13 signatures*/;
+	prepbuf[0] = 10;
+	strcpy(&prepbuf[1], s);
+	prepbuf[neededsize - 5] = 13;
+	prepbuf[neededsize - 4] = 0;
+	prepbuf[neededsize] = 0;
+
+	oldhash = 0xffffffff;
+	for(;;) {
+		if(wcfseek(f, hash, SEEK_SET) != 0) {
+			hi_unlock_file();
+			wcfclose(f);
+			return HASHINDEX_ER_IO_READ;
+		}
+
+		if(!fCheckedRead(buf, HASHINDEX_BLOCK_SIZE, f)) {
+			hi_unlock_file();
+			wcfclose(f);
+			return HASHINDEX_ER_IO_READ;
+		}
+		memcpy(&bi, buf, sizeof(bi));
+
+		//
+		//	Search for string in loaded block
+		//
+		if(mstrstr(buf+sizeof(bi), prepbuf, bi.Used) != NULL) {
+			hi_unlock_file();
+			wcfclose(f);
+			return HASHINDEX_ER_ALREADY_EXIST;
+		}
+
+		if((oldhash == 0xffffffff) && (HASHINDEX_BLOCK_SIZE >= neededsize + bi.Used + 1)) {
+			// acceptable block - so save it for future use (write data, if not exist)
+			oldhash = hash;
+		}
+
+		if(bi.Next != HASHINDEX_NULL) {
+			//
+			//	Go ahead and check next chained block
+			//
+			hash = bi.Next;
+		}
+		else {
+			//
+			//	It was the last block - add new index now
+			//
+
+			// but in what block ;-)? so we should keep first acceptable block for write to
+
+			memcpy(&prepbuf[neededsize - 4], &Index, 4);
+
+			//
+			// check for space in current block
+			//
+			if(oldhash == 0xffffffff) {
+				DWORD newhash;
+				HASHINDEX_BLOCKINFO nbi;
+				//
+				//	Need to create new hash block and link it to the chain
+				//
+				if(wcfseek(f, 0, SEEK_END) != 0) {
+					hi_unlock_file();
+					wcfclose(f);
+					return HASHINDEX_ER_IO_READ;
+				}
+				newhash = wcftell(f);
+				memset(buf, 0, HASHINDEX_BLOCK_SIZE);
+				nbi.Next = HASHINDEX_NULL;
+				nbi.Used = (WORD)(neededsize + sizeof(HASHINDEX_BLOCKINFO));
+				memcpy(buf, &nbi, sizeof(nbi));
+				memcpy(&buf[sizeof(HASHINDEX_BLOCKINFO)], prepbuf, neededsize);
+				if(!fCheckedWrite(buf, HASHINDEX_BLOCK_SIZE, f)) {
+					hi_unlock_file();
+					wcfclose(f);
+					return HASHINDEX_ER_IO_WRITE;
+				}
+				bi.Next = newhash;
+				if(wcfseek(f, hash, SEEK_SET) != 0) {
+					hi_unlock_file();
+					wcfclose(f);
+					return HASHINDEX_ER_IO_READ;
+				}
+				if(!fCheckedWrite(&bi, sizeof(bi), f)) {
+					hi_unlock_file();
+					wcfclose(f);
+					return HASHINDEX_ER_IO_WRITE;
+				}
+			}
+			else {
+				//
+				// Save to first suitable block
+				//
+				if(hash != oldhash) {
+					hash = oldhash;
+					if(wcfseek(f, hash, SEEK_SET) != 0) {
+						hi_unlock_file();
+						wcfclose(f);
+						return HASHINDEX_ER_IO_READ;
+					}
+					
+					if(!fCheckedRead(buf, HASHINDEX_BLOCK_SIZE, f)) {
+						hi_unlock_file();
+						wcfclose(f);
+						return HASHINDEX_ER_IO_READ;
+					}
+					memcpy(&bi, buf, sizeof(bi));
+				}
+
+				memcpy(&buf[bi.Used], prepbuf, neededsize + 1); // including term zero
+				bi.Used = (WORD)(bi.Used + neededsize);
+				if(wcfseek(f, hash, SEEK_SET) != 0) {
+					hi_unlock_file();
+					wcfclose(f);
+					return HASHINDEX_ER_IO_READ;
+				}
+				memcpy(buf, &bi, sizeof(bi));
+				if(!fCheckedWrite(buf, HASHINDEX_BLOCK_SIZE, f)) {
+					hi_unlock_file();
+					wcfclose(f);
+					return HASHINDEX_ER_IO_WRITE;
+				}
+			}
+
+			break;
+		}
+	}
+
+	hi_unlock_file();
+	wcfclose(f);
+
+	return HASHINDEX_ER_OK;
+}
+
+int DeleteStringFromHashedIndex(char *s)
+{
+	WCFILE *f;
+	DWORD hash;
+	HASHINDEX_BLOCKINFO bi;
+	char buf[HASHINDEX_BLOCK_SIZE];
+	char ps[MAX_HASHINDEX_STRLEN + 10];
+	char *fs;
+
+	if(strlen(s) < 3 || strlen(s) > MAX_HASHINDEX_STRLEN)
+		return HASHINDEX_ER_FORMAT;
+
+	hash = HASHINDEX_BLOCK_SIZE * hashstr(s, HASHTAB_LEN);
+
+	if((f = wcfopen(OFILE_NAME, FILE_ACCESS_MODES_RW)) == NULL)
+		return HASHINDEX_ER_IO_READ;
+	hi_lock_file();
+
+	for(;;) {
+		if(wcfseek(f, hash, SEEK_SET) != 0) {
+			hi_unlock_file();
+			return HASHINDEX_ER_IO_READ;
+		}
+		
+		if(!fCheckedRead(buf, HASHINDEX_BLOCK_SIZE, f)) {
+			hi_unlock_file();
+			return HASHINDEX_ER_IO_READ;
+		}
+
+		ps[0] = 10;
+		strcpy(&ps[1], s);
+		ps[strlen(s) + 1] = 13;
+		ps[strlen(s) + 2] = 0;
+		memcpy(&bi, buf, sizeof(bi));
+
+		//
+		//	Search for string in loaded block
+		//
+		if((fs = mstrstr(buf + sizeof(HASHINDEX_BLOCKINFO), ps, bi.Used)) != NULL) {
+			DWORD len = strlen(s) + 2 + 4;
+			//
+			//	remove from block
+			//
+			for(; (fs - buf) < bi.Used; *fs = *(fs + len), fs++);
+			memset(&(buf[bi.Used - len-1]), 0, len+1);
+
+			if(wcfseek(f, hash, SEEK_SET) != 0) {
+				hi_unlock_file();
+				return HASHINDEX_ER_IO_READ;
+			}
+			bi.Used = (WORD)(bi.Used - len);
+			memcpy(buf, &bi, sizeof(bi));
+
+			if(!fCheckedWrite(buf, HASHINDEX_BLOCK_SIZE, f)) {
+				hi_unlock_file();
+				return HASHINDEX_ER_IO_READ;
+			}
+
+			break;
+		}
+
+		if(bi.Next == HASHINDEX_NULL) {
+			hi_unlock_file();
+			wcfclose(f);
+			return HASHINDEX_ER_NOT_FOUND;
+		}
+		else hash = bi.Next;
+	}
+
+	hi_unlock_file();
+	wcfclose(f);
+
+	return HASHINDEX_ER_OK;
+}
+
+int GenerateHashwordList(char **names)
+{
+	WCFILE *f;
+	DWORD hash, pos, curalloced, bb = 0;
+	char buf[HASHINDEX_BLOCK_SIZE];
+	HASHINDEX_BLOCKINFO bi;
+	char *fs, *ss;
+
+#define GHL_REALLOC_BLOCK_SIZE 20000
+	*names = ss = (char*)malloc(GHL_REALLOC_BLOCK_SIZE);
+	*ss = 0;
+	curalloced = GHL_REALLOC_BLOCK_SIZE;
+
+	if((f = wcfopen(OFILE_NAME, FILE_ACCESS_MODES_R)) == NULL)
+		return HASHINDEX_ER_IO_CREATE;
+
+	for(hash = 0; hash < HASHTAB_LEN; hash++) {
+		pos = hash*HASHINDEX_BLOCK_SIZE;
+		for(;;) {
+			if(wcfseek(f, pos, SEEK_SET) != 0) {
+				hi_unlock_file();
+				return HASHINDEX_ER_IO_READ;
+			}
+			
+			if(!fCheckedRead(buf, HASHINDEX_BLOCK_SIZE, f)) {
+				free(*names);
+				hi_unlock_file();
+				return HASHINDEX_ER_IO_READ;
+			}
+
+			memcpy(&bi, buf, sizeof(bi));
+
+			//
+			// parse block
+			//
+			fs = buf + sizeof(bi);
+			while(*fs != 0) {
+				char *d;
+				fs++;
+				d = fs;
+				while(*d != 13) d++;
+				*d = 0;
+
+				// save result
+				strcat(ss, fs);
+				ss += strlen(fs) + 1;
+
+				// increment used memory
+				bb += strlen(fs) + 1;
+
+				*(ss - 1) = 13;
+				*ss = 0;
+				if(bb >= curalloced - 40) {
+					curalloced += GHL_REALLOC_BLOCK_SIZE;
+					*names = (char*)realloc(*names, curalloced);
+				}
+				d += 5;
+				fs = d;
+			}
+
+			if(bi.Next != HASHINDEX_NULL)
+				pos = bi.Next;
+			else break;
+		}
+	}
+
+	wcfclose(f);
+
+	return HASHINDEX_ER_OK;
+}
+
+static int compare(const void *p1, const void *p2)
+{
+	return int(*((DWORD*)p1) - *((DWORD*)p2));
+}
+
+int GenerateIndexList(DWORD **index)
+{
+	WCFILE *f;
+	DWORD hash, pos, curalloced, si = 0	/* saving index */;
+	char buf[HASHINDEX_BLOCK_SIZE];
+	HASHINDEX_BLOCKINFO bi;
+	char *fs;
+
+#define GIL_REALLOC_BLOCK_SIZE 2000*sizeof(DWORD)
+	*index = (DWORD*)malloc(GIL_REALLOC_BLOCK_SIZE);
+	curalloced = GIL_REALLOC_BLOCK_SIZE;
+
+	if((f = wcfopen(OFILE_NAME, FILE_ACCESS_MODES_R)) == NULL)
+		return HASHINDEX_ER_IO_CREATE;
+
+	for(hash = 0; hash < HASHTAB_LEN; hash++) {
+		pos = hash*HASHINDEX_BLOCK_SIZE;
+		for(;;) {
+			if(wcfseek(f, pos, SEEK_SET) != 0) {
+				hi_unlock_file();
+				return HASHINDEX_ER_IO_READ;
+			}
+			
+			if(!fCheckedRead(buf, HASHINDEX_BLOCK_SIZE, f)) {
+				free(*index);
+				hi_unlock_file();
+				return HASHINDEX_ER_IO_READ;
+			}
+
+			memcpy(&bi, buf, sizeof(bi));
+
+			//
+			// parse block
+			//
+			fs = buf + sizeof(bi);
+			while(*fs != 0) {
+				char *d;
+				fs++;
+				d = fs;
+				while(*d != 13 && *d != 0) d++;
+
+				if(*d == 0) break;
+
+				d++;
+				(*index)[si] = *((DWORD*)d);
+				si++;
+
+				if(si*sizeof(DWORD) >= curalloced - 40) {
+					curalloced += GHL_REALLOC_BLOCK_SIZE;
+					*index = (DWORD*)realloc(*index, curalloced);
+				}
+				d += 4;
+				fs = d;
+			}
+
+			if(bi.Next != HASHINDEX_NULL)
+				pos = bi.Next;
+			else break;
+		}
+	}
+
+	wcfclose(f);
+
+	qsort(((void*)(*index)), si, sizeof(DWORD), compare);
+	(*index)[si] = 0xffffffff;	// end of array
+
+	return HASHINDEX_ER_OK;
+}
blob - /dev/null
blob + c36877d09d93c498fd155210f7b4b5864b451057 (mode 644)
--- /dev/null
+++ src/hashindex.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+                      hashindex.cpp  -  hashed indexes for string include
+                             -------------------
+    begin                : Sun Nov 5 2002
+    copyright            : (C) 2001-2002 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef _HASHINDEX_H_INCLUDED_
+#define _HASHINDEX_H_INCLUDED_
+
+#include "basetypes.h"
+
+#define HASHINDEX_ER_OK				0
+#define HASHINDEX_ER_ALREADY_EXIST	1
+#define HASHINDEX_ER_NOT_FOUND		2
+#define HASHINDEX_ER_IO_CREATE		3
+#define HASHINDEX_ER_IO_READ		4
+#define HASHINDEX_ER_IO_WRITE		5
+#define HASHINDEX_ER_FORMAT			6
+
+#define HASHTAB_LEN 256
+#define HASHINDEX_BLOCK_SIZE 2000
+#define HASHINDEX_NULL	0xFFFFFFFF
+
+#define MAX_HASHINDEX_STRLEN	30
+
+typedef struct _HASHINDEX_BLOCKINFO {
+	WORD Used;
+	DWORD Next;
+} HASHINDEX_BLOCKINFO, *PHASHINDEX_BLOCKINFO;
+
+DWORD hashstr(char *s, DWORD m);
+
+int AddStringToHashedIndex(char *s, DWORD Index);
+
+int GetIndexOfString(char *s, DWORD *Index);
+
+int DeleteStringFromHashedIndex(char *s);
+
+int GenerateHashwordList(char **names);
+
+int GenerateIndexList(DWORD **index);
+
+#endif
blob - /dev/null
blob + baada3917ffece10802333a4fa9dc55a604059a1 (mode 644)
--- /dev/null
+++ src/indexer.cpp
@@ -0,0 +1,905 @@
+/***************************************************************************
+                          indexer.cpp  -  indexing support
+                             -------------------
+    begin                : Sun Apr 29 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "indexer.h"
+#include "searcher.h"
+
+#define INDEXER_RUNTIME_CHECK	0
+
+#define unlock_and_indexer_io_error0() {unlock_file(ifh);errnum = INDEXFILE_ERROR_IO_ERROR;return;}
+#define unlock_and_indexer_io_error1() {unlock_file(ifh);errnum = INDEXFILE_ERROR_IO_ERROR;return INDEXFILE_ERROR_IO_ERROR;}
+#define indexer_io_error0() {errnum = INDEXFILE_ERROR_IO_ERROR; return;}
+#define indexer_io_error1() {errnum = INDEXFILE_ERROR_IO_ERROR; return INDEXFILE_ERROR_IO_ERROR;}
+#define indexer_lock_file() {lock_file(ifh);}
+#define indexer_unlock_file() {unlock_file(ifh);}
+
+/* Indexer class constructor: open or create
+ * chartable must be NULL if CREATE_NEW not set 
+ */
+CIndexFile::CIndexFile(char *ifname, DWORD flags, WORD chartablelen, char *chartable, DWORD maxi)
+{
+	init = 0;
+	DWORD i;
+
+	iblock = (SSymbolIndex *)malloc(sizeof(SSymbolIndex)*chartablelen);
+
+	if((flags & INDEXFILE_CREATE_BOTH) != 0)
+	{
+		/* open existing index file */
+		if((ifh = wcfopen(ifname, FILE_ACCESS_MODES_RW)) != NULL)
+		{
+			char *sign = (char*)malloc(strlen(INDEXFILE_FILE_SIGNATURE) + 1);
+			if(wcfread(sign, 1, strlen(INDEXFILE_FILE_SIGNATURE), ifh) !=
+				strlen(INDEXFILE_FILE_SIGNATURE))
+			{
+				free(sign);
+				flags = INDEXFILE_CREATE_NEW;
+			}
+			if(strncmp(sign, INDEXFILE_FILE_SIGNATURE, strlen(INDEXFILE_FILE_SIGNATURE)) != 0)
+			{
+				errnum = INDEXFILE_ERROR_INVALID_FILE;
+				free(sign);
+				flags = INDEXFILE_CREATE_NEW;
+			}
+			free(sign);
+			flags = INDEXFILE_CREATE_EXISTING;
+		}
+		else
+		{
+			flags = INDEXFILE_CREATE_NEW;
+		}
+	}
+
+	if((flags & INDEXFILE_CREATE_NEW) != 0)
+	{
+		/* create new index file */
+		if((ifh = wcfopen(ifname, FILE_ACCESS_MODES_CW)) != NULL)
+		{
+			indexer_lock_file();
+			/* wrtie signature */
+			if(wcfwrite(INDEXFILE_FILE_SIGNATURE, 1, strlen(INDEXFILE_FILE_SIGNATURE), ifh) !=
+				strlen(INDEXFILE_FILE_SIGNATURE))
+			{
+				free(iblock);
+				unlock_and_indexer_io_error0();
+			}
+			/*  write max indexing length (maxi) */
+			if(wcfwrite(&maxi, 1, sizeof(maxi), ifh) != sizeof(maxi))
+			{
+				free(iblock);
+				unlock_and_indexer_io_error0();
+			}
+			/* write symbol count and table */
+			if(wcfwrite(&chartablelen, 1, sizeof(chartablelen), ifh) != sizeof(chartablelen))
+			{
+				free(iblock);
+				unlock_and_indexer_io_error0();
+			}
+			if(wcfwrite(chartable, 1, chartablelen, ifh) != chartablelen)
+			{
+				free(iblock);
+				unlock_and_indexer_io_error0();
+			}
+
+			memset(iblock, 0xFF, chartablelen*sizeof(SSymbolIndex));
+			if(wcfwrite(iblock, 1, chartablelen*sizeof(SSymbolIndex), ifh) != chartablelen*sizeof(SSymbolIndex))
+			{
+				free(iblock);
+				unlock_and_indexer_io_error0();
+			}
+
+			indexer_unlock_file();
+			wcfclose(ifh);
+		}
+		else indexer_io_error0();
+		flags = INDEXFILE_CREATE_EXISTING;
+	}
+
+	if((flags & INDEXFILE_CREATE_EXISTING) != 0)
+	{
+		/* open existing index file */
+		if((ifh = wcfopen(ifname, FILE_ACCESS_MODES_RW)) != NULL)
+		{
+			char *sign = (char*)malloc(strlen(INDEXFILE_FILE_SIGNATURE) + 1);
+			if(wcfread(sign, 1, strlen(INDEXFILE_FILE_SIGNATURE), ifh) !=
+				strlen(INDEXFILE_FILE_SIGNATURE))
+			{
+				free(sign);
+				free(iblock);
+				indexer_io_error0();
+			}
+			if(strncmp(sign, INDEXFILE_FILE_SIGNATURE, strlen(INDEXFILE_FILE_SIGNATURE)) != 0)
+			{
+				errnum = INDEXFILE_ERROR_INVALID_FILE;
+				free(sign);
+				free(iblock);
+				return;
+			}
+			free(sign);
+
+			/* read maximum index length */
+			if(wcfread(&maxindex, 1, sizeof(maxindex), ifh) != sizeof(maxindex))
+			{
+				free(iblock);
+				indexer_io_error0();
+			}
+			/* read symbolic count */
+			if(wcfread(&symcount, 1, sizeof(symcount), ifh) != sizeof(symcount))
+			{
+				free(iblock);
+				indexer_io_error0();
+			}
+			// realloc iblock for new symcount
+			iblock = (SSymbolIndex *)realloc(iblock, sizeof(SSymbolIndex)*symcount);
+
+			char *chartbl = (char*)malloc(symcount + 10);
+			if(wcfread(chartbl, 1, symcount, ifh) != symcount)
+			{
+				free(chartbl);
+				indexer_io_error0();
+			}
+			/* prepare index of the begining */
+			begin_pos = wcftell(ifh);
+			
+			if(wcfread(iblock, 1, symcount*sizeof(SSymbolIndex), ifh) != symcount*sizeof(SSymbolIndex))
+			{
+				free(iblock);
+				free(chartbl);
+				indexer_io_error0()
+			}
+			// prepare symtable indexes
+			for(i = 0; i < INDEXFILE_MAX_CHARTABLE; i++) symtable[i] = INDEXFILE_MAX_CHARTABLE;
+			for(i = 0; i < symcount; i++)
+				symtable[(unsigned char)chartbl[i]] = (unsigned char)i;
+			free(chartbl);
+			// Activate cache
+			CacheROOT = AllocCacheBlock(symcount);
+			memcpy(CacheROOT->II, iblock, sizeof(SSymbolIndex)*symcount);
+		}
+		else {
+			free(iblock);
+			indexer_io_error0();
+		}
+
+		init = 1;
+		errnum = INDEXFILE_ERROR_ALLOK;
+		// save file name
+		CIndexFile::ifname = (char*)malloc(strlen(ifname) + 1);
+		strcpy(CIndexFile::ifname, ifname);
+		// make empty block
+		iblockFF = (SSymbolIndex*)malloc(sizeof(SSymbolIndex)*symcount);
+		memset(iblockFF, 0xFF, sizeof(SSymbolIndex)*symcount);
+		return;
+	}
+}
+
+CIndexFile::~CIndexFile()
+{
+	if(init)
+	{
+		DWORD lev = 0;
+		DWORD j[FIRST_LEVELS_CACHE_SIZE];
+		int recursion = 0;
+		DWORD begfrom = 0;
+		SCacheElIndex *tcb[FIRST_LEVELS_CACHE_SIZE];
+		tcb[0] = CacheROOT;
+		if(wcfseek(ifh, begin_pos, SEEK_SET) != 0)
+		{
+			indexer_io_error0();
+		}
+		if(wcfwrite(tcb[lev]->II, 1, symcount*sizeof(SSymbolIndex), ifh) != symcount*sizeof(SSymbolIndex)) 
+		{
+			indexer_io_error0()
+		}
+
+		for(;;)
+		{
+
+			for(j[lev] = begfrom; j[lev] < symcount; j[lev]++)
+			{
+				if((DWORD)tcb[lev]->IM[j[lev]] != INDEXFILE_NO_INDEX)
+				{
+					if(wcfseek(ifh, tcb[lev]->II[j[lev]].Index, SEEK_SET) != 0)
+					{
+						indexer_io_error0();
+					}
+					if(wcfwrite(tcb[lev]->IM[j[lev]]->II, 1, symcount*sizeof(SSymbolIndex), ifh) != symcount*sizeof(SSymbolIndex))
+					{
+						indexer_io_error0()
+					}
+					lev++;
+					tcb[lev] = tcb[lev-1]->IM[j[lev-1]];
+					recursion = 1;
+					break;
+				}
+			}
+			if(!recursion)
+			{
+				FreeCacheBlock(tcb[lev]);
+				if(lev) lev--; 
+				else break; // go out at all
+				j[lev]++;
+				begfrom = j[lev];
+			}
+			else
+			{
+				begfrom = 0;
+				recursion = 0;
+			}
+		}
+
+		free(ifname);
+		free(iblock);
+		free(iblockFF);
+		wcfclose(ifh);
+	}
+}
+
+
+/* Allocate cache block for defined symcount
+ * if successfull returns pointer to SCacheElIndex, otherwise returns NULL
+ */
+SCacheElIndex* CIndexFile::AllocCacheBlock(DWORD symcount)
+{
+	SCacheElIndex *p;
+	p = (SCacheElIndex*)malloc(sizeof(SCacheElIndex));
+	if(!p) return p;
+	p->II = new SSymbolIndex[symcount];
+	if(!p->II)
+	{
+		free(p);
+		return NULL;
+	}
+	memset(p->II, 0xFF, sizeof(SSymbolIndex)*symcount);
+	p->IM = (SCacheElIndex**)malloc(sizeof(SCacheElIndex*)*symcount);
+	if(!p->IM)
+	{
+		free(p->II);
+		free(p);
+		return NULL;
+	}
+	memset(p->IM, 0xFF, sizeof(SCacheElIndex*)*symcount);
+	return p;
+}
+
+
+/* Free cache block
+ */
+int CIndexFile::FreeCacheBlock(SCacheElIndex *cb)
+{
+	free(cb->II);
+	free(cb->IM);
+	free(cb);
+	return 1;
+}
+
+
+/* Test if word [iword] is compartible with current index file
+ * return 1 if compartible, otherwise 0
+ */
+DWORD CIndexFile::TestIndexWord(char *iword)
+{
+	for(DWORD i = 0; i < strlen(iword); i++)
+	{
+		if(((unsigned char)iword[i]) > INDEXFILE_MAX_CHARTABLE || symtable[(unsigned char)iword[i]] == INDEXFILE_MAX_CHARTABLE)
+		{
+			return 0;
+		}
+	}
+	return 1;
+}
+
+/* put new index entry for word iword to indexes,
+ * if index already exist it return INDEXFILE_ERROR_INDEX_ALREADY_EXIST
+ */
+//DWORD CIndexFile::PutIndexByWord(char *iword, DWORD LocIndex)
+//{
+//	DWORD indlength, curpos, cpos, i;
+//	SCacheElIndex *bcache;
+//	SSymbolIndex *iblk;
+//
+//#if INDEXER_RUNTIME_CHECK
+//	if(ifh == NULL)
+//	{
+//		errnum = INDEXFILE_ERROR_INVALID_FILE;
+//		return errnum;
+//	}
+//	if(TestIndexWord(iword) == 0)
+//	{
+//		errnum = INDEXFILE_ERROR_INVALID_WORD;
+//		return errnum;
+//	}
+//#endif
+//
+//	DWORD strlen_iword = (DWORD)strlen(iword);
+//
+//	if(strlen_iword != 0 && strlen_iword <= INDEXFILE_MAX_INDEXING_WORD_LENGTH)
+//	{
+//		curpos = begin_pos;
+//		indexer_lock_file();
+//
+//		// prepare cache
+//		bcache = CacheROOT;
+//
+//		if(strlen_iword > maxindex) indlength = maxindex;
+//		else indlength = strlen_iword;
+//
+//		for(i = 0; i < indlength; i++)
+//		{
+//			if(i < FIRST_LEVELS_CACHE_SIZE)
+//			{
+//				if(i != 0)
+//				{
+//					bcache = bcache->IM[cpos];
+//				}
+//				iblk = bcache->II;
+//			}
+//			else
+//			{
+//				iblk = iblock;
+//				if(wcfseek(ifh, curpos, SEEK_SET) != 0)
+//				{
+//					unlock_and_indexer_io_error1();
+//				}
+//				if(wcfread(iblk, 1, sizeof(SSymbolIndex)*symcount, ifh) != sizeof(SSymbolIndex)*symcount)
+//				{
+//					unlock_and_indexer_io_error1();
+//				}
+//			}
+//
+//			cpos = symtable[(unsigned char)iword[i]];
+//
+//			if(iblk[cpos].Index == INDEXFILE_NO_INDEX && i != indlength - 1)
+//			{
+//				// create new block - we should write it to disk PERMANENTLY !
+//
+//				if(wcfseek(ifh, 0, SEEK_END) != 0)
+//				{
+//					unlock_and_indexer_io_error1();
+//				}
+//				DWORD fpos = wcftell(ifh);
+//				if(wcfwrite(iblockFF, 1, symcount*sizeof(SSymbolIndex), ifh) != symcount*sizeof(SSymbolIndex))
+//				{
+//					unlock_and_indexer_io_error1();
+//				}
+//
+//				// now we decide what we should do: write new index to cache or to disk
+//				// and where we will allocate new block - in cache or on drive
+//				if(i < FIRST_LEVELS_CACHE_SIZE)
+//				{
+//					if(i < FIRST_LEVELS_CACHE_SIZE - 1)
+//					{
+//						// write to cache and allocate new in cache
+//						bcache->IM[cpos] = AllocCacheBlock(symcount);
+//						// write new index to cache
+//						bcache->II[cpos].Index = fpos;
+//					}
+//					else
+//					{
+//						// write to cache but allocate new on disk
+//						bcache->II[cpos].Index = fpos;
+//					}
+//					curpos = bcache->II[cpos].Index;
+//				}
+//				else
+//				{
+//					// write to disk and allocate new on disk
+//					iblk[cpos].Index = fpos;
+//					if(wcfseek(ifh, curpos, SEEK_SET) != 0)
+//					{
+//						unlock_and_indexer_io_error1();
+//					}
+//					if(wcfwrite(iblk, 1, symcount*sizeof(SSymbolIndex), ifh) != symcount*sizeof(SSymbolIndex))
+//					{
+//						unlock_and_indexer_io_error1();
+//					}
+//					curpos = iblk[cpos].Index;
+//				}
+//			}
+//			else
+//			{
+//				if(i != indlength - 1)
+//				{
+//					curpos = iblk[cpos].Index;
+//					if(i < FIRST_LEVELS_CACHE_SIZE - 1 && (DWORD)bcache->IM[cpos] == INDEXFILE_NO_INDEX)
+//					{
+//						// load to cache, if we need it
+//
+//						// allocate block
+//						bcache->IM[cpos] = AllocCacheBlock(symcount);
+//
+//						// and read index from disk
+//						if(wcfseek(ifh, iblk[cpos].Index, SEEK_SET) != 0)
+//						{
+//							unlock_and_indexer_io_error1();
+//						}
+//						if(wcfread(bcache->IM[cpos]->II, 1, sizeof(SSymbolIndex)*symcount, ifh) != sizeof(SSymbolIndex)*symcount)
+//						{
+//							unlock_and_indexer_io_error1();
+//						}
+//					}
+//				}
+//			}//of else
+//		}
+//
+//		if(iblk[cpos].Location != INDEXFILE_NO_INDEX)
+//		{
+//			indexer_unlock_file();
+//			errnum = INDEXFILE_ERROR_INDEX_ALREADY_EXIST;
+//			return errnum;
+//		}
+//		else {
+//			// save index
+//			iblk[cpos].Location = LocIndex;
+//			if(indlength > FIRST_LEVELS_CACHE_SIZE)
+//			{
+//				// write to drive
+//				if(wcfseek(ifh, curpos, SEEK_SET) != 0)
+//				{
+//					unlock_and_indexer_io_error1();
+//				}
+//				DWORD rr = (DWORD)wcfwrite(iblk, 1, symcount*sizeof(SSymbolIndex), ifh);
+//				indexer_unlock_file();
+//				if(rr != symcount*sizeof(SSymbolIndex))
+//				{
+//					indexer_io_error1();
+//				}
+//			}
+//		}
+//	}
+//	else
+//	{
+//		errnum = INDEXFILE_ERROR_INVALID_WORD;
+//		return errnum;
+//	}
+//	errnum = INDEXFILE_ERROR_ALLOK;
+//	return errnum;
+//}
+
+
+/* put new index entry for word iword to indexes,
+ * if index is not the same for subwords functions aborts and return
+ * INDEXFILE_ERROR_EXIST_DIFF_INDEX
+ * BEFORE CALLING THIS FUNCTION : Should be set AddingMId at CMessageSearcher because of 
+ * this function using calls to CMessageSearcher::AddMessageToRefBlock() and AllocRefBlock()
+ ***********************************************************************
+ * THERE IS SOME ADMISSION : IF there is an index for word with lenght n 
+ * => we should have also index for all words between MinLenght and default 
+ * word length. If say other it means that if you are using this functions you can't
+ * in addition to use PutIndexByWord, because of database corruption will take place.
+ */
+DWORD CIndexFile::PutOrGetIndexByWordAssoc(char *iword, BYTE MinLength, void *vpms)// DWORD NewBlockMark, DWORD NewBlockDelta)
+{
+	CMessageSearcher *pMS = (CMessageSearcher*)vpms;
+	DWORD indlength, curpos, cpos, NewLocation;
+	DWORD i;
+	SCacheElIndex *bcache;
+	SSymbolIndex *iblk;
+
+#if INDEXER_RUNTIME_CHECK
+	if(ifh == NULL)
+	{
+		errnum = INDEXFILE_ERROR_INVALID_FILE;
+		return errnum;
+	}
+	if(TestIndexWord(iword) == 0)
+	{
+		errnum = INDEXFILE_ERROR_INVALID_WORD;
+		return errnum;
+	}
+#endif
+
+	DWORD strlen_iword = (DWORD)strlen(iword);
+
+	if(strlen_iword != 0 && strlen_iword <= INDEXFILE_MAX_INDEXING_WORD_LENGTH)
+	{
+		curpos = begin_pos;
+		indexer_lock_file();
+
+		// prepare cache
+		bcache = CacheROOT;
+
+		if(strlen_iword > maxindex) indlength = maxindex;
+		else indlength = strlen_iword;
+
+		for(i = 0; i < indlength; i++)
+		{
+			if(i < FIRST_LEVELS_CACHE_SIZE)
+			{
+				if(i != 0)
+				{
+					bcache = bcache->IM[cpos];
+				}
+				iblk = bcache->II;
+			}
+			else
+			{
+				iblk = iblock;
+				if(wcfseek(ifh, curpos, SEEK_SET) != 0)
+				{
+					unlock_and_indexer_io_error1();
+				}
+				if(wcfread(iblk, 1, sizeof(SSymbolIndex)*symcount, ifh) != sizeof(SSymbolIndex)*symcount)
+				{
+					unlock_and_indexer_io_error1();
+				}
+			}
+
+			cpos = symtable[(unsigned char)iword[i]];
+
+			// add new id to block, update location if new block is created
+			if(i >= MinLength)
+			{
+				NewLocation = pMS->AddMessageToRefBlock(iblk[cpos].Location);
+				if(NewLocation != iblk[cpos].Location && i >= FIRST_LEVELS_CACHE_SIZE) {
+					iblk[cpos].Location = NewLocation;
+					// update with new index only in case we are missing cache =)
+					if(wcfseek(ifh, curpos, SEEK_SET) != 0)
+					{
+						unlock_and_indexer_io_error1();
+					}
+					if(wcfwrite(iblk, 1, symcount*sizeof(SSymbolIndex), ifh) != symcount*sizeof(SSymbolIndex))
+					{
+						unlock_and_indexer_io_error1();
+					}
+				}
+				else iblk[cpos].Location = NewLocation;
+			}
+
+			// go else
+			if(iblk[cpos].Index == INDEXFILE_NO_INDEX && i != indlength - 1)
+			{
+				// create new block - we should write it to disk PERMANENTLY !
+
+				if(wcfseek(ifh, 0, SEEK_END) != 0)
+				{
+					unlock_and_indexer_io_error1();
+				}
+				DWORD fpos = wcftell(ifh);
+				if(wcfwrite(iblockFF, 1, symcount*sizeof(SSymbolIndex), ifh) != symcount*sizeof(SSymbolIndex))
+				{
+					unlock_and_indexer_io_error1();
+				}
+
+				// now we decide what we should do: write new index to cache or to disk
+				// and where we will allocate new block - in cache or on drive
+				if(i < FIRST_LEVELS_CACHE_SIZE)
+				{
+					// write new index to cache
+					bcache->II[cpos].Index = fpos;
+					if(i < FIRST_LEVELS_CACHE_SIZE - 1)
+					{
+						// write to cache and allocate new in cache
+						bcache->IM[cpos] = AllocCacheBlock(symcount);
+					}
+					curpos = bcache->II[cpos].Index;
+				}
+				else
+				{
+					// write to disk and allocate new on disk
+					iblk[cpos].Index = fpos;
+					if(wcfseek(ifh, curpos, SEEK_SET) != 0)
+					{
+						unlock_and_indexer_io_error1();
+					}
+					if(wcfwrite(iblk, 1, symcount*sizeof(SSymbolIndex), ifh) != symcount*sizeof(SSymbolIndex))
+					{
+						unlock_and_indexer_io_error1();
+					}
+					curpos = iblk[cpos].Index;
+				}
+			}
+			else
+			{
+				if(i != indlength - 1)
+				{
+					curpos = iblk[cpos].Index;
+					if(i < FIRST_LEVELS_CACHE_SIZE - 1 && (DWORD)bcache->IM[cpos] == INDEXFILE_NO_INDEX)
+					{
+						// load to cache, if we need it
+
+						// allocate block
+						bcache->IM[cpos] = AllocCacheBlock(symcount);
+
+						// and read index from disk
+						if(wcfseek(ifh, iblk[cpos].Index, SEEK_SET) != 0)
+						{
+							unlock_and_indexer_io_error1();
+						}
+						if(wcfread(bcache->IM[cpos]->II, 1, sizeof(SSymbolIndex)*symcount, ifh) != sizeof(SSymbolIndex)*symcount)
+						{
+							unlock_and_indexer_io_error1();
+						}
+					}
+				}
+			}//of else
+		}
+		// condition 
+		// iblk[cpos].Location != INDEXFILE_NO_INDEX
+		// will be true always
+
+		if(indlength > FIRST_LEVELS_CACHE_SIZE)
+		{
+			// save index
+			if(wcfseek(ifh, curpos, SEEK_SET) != 0)
+			{
+				unlock_and_indexer_io_error1();
+			}
+			DWORD rr = (DWORD)wcfwrite(iblk, 1, symcount*sizeof(SSymbolIndex), ifh);
+			if(rr != symcount*sizeof(SSymbolIndex))
+			{
+				unlock_and_indexer_io_error1();
+			}
+		}
+		indexer_unlock_file();
+		errnum = INDEXFILE_ERROR_ALLOK;
+		return errnum;
+	}
+	else
+	{
+		errnum = INDEXFILE_ERROR_INVALID_WORD;
+		return errnum;
+	}
+}
+
+
+/* get index entry for word [iword]
+ * return values: if index exist return INDEXFILE_ALLOK and if LocIndex not NULL
+ * store here returning index, and also if it is uniq index  and exact not NULL 
+ * set exact set it = 1, otherwise = 0, 
+ * if index not exist return INDEXFILE_INDEX_NOT_EXIST
+ */
+DWORD CIndexFile::GetIndexByWord(char *iword, DWORD *LocIndex, int *exact)
+{
+	DWORD curpos, i, cpos;
+	DWORD indlength;
+	SCacheElIndex *bcache;
+	SSymbolIndex *iblk;
+
+#if INDEXER_RUNTIME_CHECK
+	if(ifh == NULL || iblock == NULL)
+	{
+		errnum = INDEXFILE_ERROR_INVALID_FILE;
+		return errnum;
+	}
+	if(TestIndexWord(iword) == 0)
+	{
+		errnum = INDEXFILE_ERROR_INVALID_WORD;
+		return errnum;
+	}
+#endif
+
+	DWORD strlen_iword = (DWORD)strlen(iword); // just for optimizing
+
+	if(strlen_iword > 1)
+	{
+		curpos = begin_pos;
+
+		// prepare cache
+		bcache = CacheROOT;
+
+		if(strlen_iword > maxindex) indlength = maxindex;
+		else indlength = strlen_iword;
+
+		for(i = 0; i < indlength; i++)
+		{
+
+			if(i < FIRST_LEVELS_CACHE_SIZE)
+			{
+				if(i != 0)
+				{
+					if((DWORD)bcache->IM[cpos] == INDEXFILE_NO_INDEX)
+					{
+						// load to cache
+
+						// allocate block
+						bcache->IM[cpos] = AllocCacheBlock(symcount);
+
+						// and read index from disk
+						if(wcfseek(ifh, iblk[cpos].Index, SEEK_SET) != 0)
+						{
+							unlock_and_indexer_io_error1();
+						}
+						if(wcfread(bcache->IM[cpos]->II, 1, sizeof(SSymbolIndex)*symcount, ifh) != sizeof(SSymbolIndex)*symcount)
+						{
+							unlock_and_indexer_io_error1();
+						}
+
+					}
+					// get it from cache
+					bcache = bcache->IM[cpos];
+				}
+				iblk = bcache->II;
+			}
+			else
+			{
+				iblk = iblock;
+				if(wcfseek(ifh, curpos, SEEK_SET) != 0)
+				{
+					unlock_and_indexer_io_error1();
+				}
+				if(wcfread(iblk, 1, sizeof(SSymbolIndex)*symcount, ifh) != sizeof(SSymbolIndex)*symcount)
+				{
+					unlock_and_indexer_io_error1();
+				}
+			}
+
+			cpos = symtable[(unsigned char)iword[i]];
+
+			if(i != indlength - 1)
+			{
+				if(iblk[cpos].Index == INDEXFILE_NO_INDEX)
+				{
+					errnum = INDEXFILE_ERROR_INDEX_NOT_EXIST;
+					return errnum;
+				}
+				else
+				{
+					curpos = iblk[cpos].Index;
+				}
+			}
+		}
+
+		if(LocIndex != NULL) *LocIndex = iblk[cpos].Location;
+		if(exact != NULL)
+		{
+			if(strlen_iword <= maxindex) *exact = 1;
+			else *exact = 0;
+		}
+		errnum = INDEXFILE_ERROR_ALLOK;
+		return errnum;
+	}
+	else
+	{
+		errnum = INDEXFILE_ERROR_INVALID_WORD;
+		return errnum;
+	}
+}
+
+
+/* NEW VERSION DOESN'T TESTED AT ALL !!! */
+
+/* modify index associated with word [iword] to NewLocIndex if oldLocIndex equal 
+ * modifying index otherwise return error code (INDEXFILE_ERROR_INDEX_NOT_EXIST 
+ * returned in that case if oldLocIndex != index of modifying word)
+ * (if it need to delete index - NewLocIndex should be set to INDEXFILE_NO_INDEX)
+ */
+DWORD CIndexFile::ModifyIndexByWord(char *iword, DWORD oldLocIndex, DWORD NewLocIndex)
+{
+	DWORD curpos, i, cpos;
+	DWORD indlength;
+	SCacheElIndex *bcache;
+	SSymbolIndex *iblk;
+
+#if INDEXER_RUNTIME_CHECK
+	if(ifh == NULL)
+	{
+		errnum = INDEXFILE_ERROR_INVALID_FILE;
+		return errnum;
+	}
+	if(TestIndexWord(iword) == 0)
+	{
+		errnum = INDEXFILE_ERROR_INVALID_WORD;
+		return errnum;
+	}
+#endif
+
+	DWORD strlen_iword = (DWORD)strlen(iword); // just for optimizing
+
+	if(strlen_iword > 1)
+	{
+		curpos = begin_pos;
+
+		// prepare cache
+		bcache = CacheROOT;
+
+		if(strlen_iword > maxindex) indlength = maxindex;
+		else indlength = strlen_iword;
+
+		for(i = 0; i < indlength; i++)
+		{
+			if(i < FIRST_LEVELS_CACHE_SIZE)
+			{
+				if(i != 0)
+				{
+					if((DWORD)bcache->IM[cpos] == INDEXFILE_NO_INDEX)
+					{
+						// load to cache
+
+						// allocate block
+						bcache->IM[cpos] = AllocCacheBlock(symcount);
+
+						// and read index from disk
+						if(wcfseek(ifh, iblk[cpos].Index, SEEK_SET) != 0)
+						{
+							unlock_and_indexer_io_error1();
+						}
+						if(wcfread(bcache->IM[cpos]->II, 1, sizeof(SSymbolIndex)*symcount, ifh) != sizeof(SSymbolIndex)*symcount)
+						{
+							unlock_and_indexer_io_error1();
+						}
+
+					}
+					// get it from cache
+					bcache = bcache->IM[cpos];
+				}
+				iblk = bcache->II;
+			}
+			else
+			{
+				iblk = iblock;
+				if(wcfseek(ifh, curpos, SEEK_SET) != 0)
+				{
+					unlock_and_indexer_io_error1();
+				}
+				if(wcfread(iblk, 1, sizeof(SSymbolIndex)*symcount, ifh) != sizeof(SSymbolIndex)*symcount)
+				{
+					unlock_and_indexer_io_error1();
+				}
+			}
+
+			cpos = symtable[(unsigned char)iword[i]];
+
+			if(iblk[cpos].Index == INDEXFILE_NO_INDEX)
+			{
+				errnum = INDEXFILE_ERROR_INDEX_NOT_EXIST;
+				return errnum;
+			}
+			else
+			{
+				if(i != indlength - 1)
+				{
+					curpos = iblk[cpos].Index;
+				}
+			}
+		}
+
+		if(iblk[cpos].Location == INDEXFILE_NO_INDEX)
+		{
+			errnum = INDEXFILE_ERROR_INDEX_NOT_EXIST;
+			return errnum;
+		}
+		else
+		{
+			if(oldLocIndex != iblk[cpos].Location)
+			{
+				errnum = INDEXFILE_ERROR_INDEX_NOT_EXIST;
+				return errnum;
+			}
+			else
+			{
+				iblk[cpos].Location = NewLocIndex;
+				if(indlength > FIRST_LEVELS_CACHE_SIZE)
+				{
+					// save index
+					indexer_lock_file();
+					if(wcfseek(ifh, curpos, SEEK_SET) != 0)
+					{
+						unlock_and_indexer_io_error1();
+					}
+					DWORD rr = (DWORD)wcfwrite(iblk, 1, symcount*sizeof(SSymbolIndex), ifh);
+					indexer_unlock_file();
+
+					if(rr != symcount*sizeof(SSymbolIndex))
+					{
+						indexer_io_error1();
+					}
+				}
+
+				errnum = INDEXFILE_ERROR_ALLOK;
+				return errnum;
+			}
+		}
+	}
+	else
+	{
+		errnum = INDEXFILE_ERROR_INVALID_WORD;
+		return errnum;
+	}
+}
blob - /dev/null
blob + d7e3730f9f37a78de27988ad647ab8b6d94e2f03 (mode 644)
--- /dev/null
+++ src/indexer.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+                          indexer.h  -  indexing support include
+                             -------------------
+    begin                : Sun Apr 29 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef INDEXER_H_INCLUDED
+#define INDEXER_H_INCLUDED
+
+#include "basetypes.h"
+
+// Perfomance releative params
+// Higher is better, but will take more memory
+#define FIRST_LEVELS_CACHE_SIZE		5
+
+// Common unmodif. params
+#define INDEXFILE_MAX_CHARTABLE 256
+#define INDEXFILE_FILE_SIGNATURE "wc-idx"
+#define INDEXFILE_MAX_INDEXING_WORD_LENGTH 255
+
+/* indexer error codes */
+#define INDEXFILE_ERROR_ALLOK				0
+#define INDEXFILE_ERROR_NOT_INITIALIZED		1
+#define INDEXFILE_ERROR_IO_ERROR			2
+#define INDEXFILE_ERROR_INVALID_FILE		3
+#define INDEXFILE_ERROR_INVALID_WORD		4
+#define INDEXFILE_ERROR_INDEX_ALREADY_EXIST	5
+#define INDEXFILE_ERROR_INDEX_NOT_EXIST		6
+#define INDEXFILE_ERROR_EXIST_DIFF_INDEX	7
+
+#define INDEXFILE_CREATE_NEW			0x0001
+#define INDEXFILE_CREATE_EXISTING		0x0002
+#define INDEXFILE_CREATE_BOTH			0x0004
+
+#define INDEXFILE_NO_INDEX			0xFFFFFFFF
+
+/* Index element structure */
+struct SSymbolIndex {
+	DWORD Index;
+	DWORD Location;
+};
+
+/* Cache elements structure */
+struct SCacheElIndex;
+
+struct SCacheElIndex {
+	SSymbolIndex *II;	// File info
+	SCacheElIndex **IM;	// Memory references
+};
+
+class CIndexFile {
+protected:
+	WCFILE *ifh;
+	WORD symcount;
+	WORD symtable[INDEXFILE_MAX_CHARTABLE];
+	DWORD begin_pos, maxindex;
+	SSymbolIndex *iblock, *iblockFF;
+	char *ifname;
+	int init;
+
+	SCacheElIndex *CacheROOT;		// ROOT element of cache block structure
+	SCacheElIndex* AllocCacheBlock(DWORD symcount);
+	int FreeCacheBlock(SCacheElIndex *cb);
+public:
+	CIndexFile(char *ifname, DWORD flags, WORD chartablelen, char *chartable, DWORD maxi);
+	~CIndexFile();
+	DWORD errnum;
+
+	DWORD TestIndexWord(char *iword);
+//	DWORD PutIndexByWord(char *iword, DWORD LocIndex);
+	DWORD PutOrGetIndexByWordAssoc(char *iword, BYTE MinLength, void *vpms);
+	DWORD GetIndexByWord(char *iword, DWORD *LocIndex, int *exact);
+	DWORD ModifyIndexByWord(char *iword, DWORD oldLocIndex, DWORD NewLocIndex);
+};
+
+#endif
blob - /dev/null
blob + bd10691123d34b103b07ff7946b90474305fa5ce (mode 644)
--- /dev/null
+++ src/logins.cpp
@@ -0,0 +1,595 @@
+/***************************************************************************
+                          login.cpp  -  log in/out support
+                             -------------------
+    begin                : Sun Apr 29 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "security.h"
+#include "logins.h"
+#include "error.h"
+
+#define unlock_and_logins_io_error() {unlock_file(f); wcfclose(f); return 0;}
+#define logins_lock_file() {lock_file(f);}
+#define logins_unlock_file() {unlock_file(f);}
+
+/* create authorization sequence with ttl - Time To Live for user *ui
+ * and store it to ui.ID
+ * return 1 if successfull, otherwise zero returned
+ */
+DWORD OpenAuthSequence(int ttl, SSavedAuthSeq *ui)
+{
+	SSavedAuthSeq *buf;
+	WCFILE *f;
+	int el;
+	DWORD id, id1, rr, i, ii;
+
+	/* set creation time */
+	time_t tn = time(NULL);
+
+	if((f = wcfopen(F_AUTHSEQ, FILE_ACCESS_MODES_RW)) == NULL) {
+		// if file doesn't exist - create it
+		if((f = wcfopen(F_AUTHSEQ, FILE_ACCESS_MODES_CW)) == NULL) {
+			return 0;
+		}
+		else {
+			wcfclose(f);
+			if((f = wcfopen(F_AUTHSEQ, FILE_ACCESS_MODES_RW)) == NULL) {
+				return 0;
+			}
+		}
+	}
+	buf = (SSavedAuthSeq*)malloc(sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT);
+
+	/******** lock f ********/
+	logins_lock_file();
+
+	ii = 0;
+	while(!wcfeof(f)) {
+		if((rr = wcfread(((char*)buf + ii*sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT), 1, sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT, f)) !=
+			sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT) {
+			if((rr%sizeof(SSavedAuthSeq)) != 0) {
+				free(buf);
+				unlock_and_logins_io_error();
+			}
+		}
+		ii++;
+		buf = (SSavedAuthSeq*)realloc(buf, (ii+1)*sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT);
+	}
+
+	// Generate random sequence for user session
+	// if generated sequence exist regenerate it again
+L_Try:
+//	print2log("->>> %d", ((ii-1)*SEQUENCE_READ_COUNT + (rr+1)/sizeof(SAuthUserSeq)));
+	id = rand32();
+	id1 = rand32();
+	el = -1;
+	for(i = 0; i < ((ii-1)*SEQUENCE_READ_COUNT + (rr+1)/sizeof(SSavedAuthSeq)); i++) {
+		if(buf[i].ID[0] == id && buf[i].ID[1] == id1)
+			goto L_Try;
+		if(buf[i].ExpireDate < tn) {
+			if(el < 0) el = i;
+		}
+	}
+
+	free(buf);
+
+	// Sequence was successfully generated, save it
+	ui->ID[0] = id;
+	ui->ID[1] = id1;
+	ui->ExpireDate = time(NULL) + ttl;
+
+	if(el < 0) {
+		if(wcfseek(f, 0, SEEK_END) < 0)
+			unlock_and_logins_io_error();
+	}
+	else {
+		if(wcfseek(f, el*sizeof(SSavedAuthSeq), SEEK_SET) < 0)
+			unlock_and_logins_io_error();
+	}
+
+	if(!fCheckedWrite(ui, sizeof(SSavedAuthSeq), f))
+		unlock_and_logins_io_error();
+
+	logins_unlock_file();
+	/********* unlock f *********/
+
+	wcfclose(f);
+	return 1;
+}
+
+/* close authorization sequence by Session id (=id) or userId (=Uid)
+ * return 1 if successfull otherwise 0 returned
+ */
+int CloseAuthSequence(DWORD id[2], DWORD Uid)
+{
+	SSavedAuthSeq *buf = NULL;
+	WCFILE *f;
+	DWORD rr, i, ii = 0;
+	time_t tn = time(NULL);
+
+	if(( (id[0] != 0 || id[1] != 0) && Uid != 0) || (id[0] == 0 && id[1] == 0 && Uid == 0))
+		return 0;	// incorrect params
+	
+	if((f = wcfopen(F_AUTHSEQ, FILE_ACCESS_MODES_RW)) == NULL)
+		return 0;
+
+	buf = (SSavedAuthSeq*)malloc(sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT);
+
+	//******** lock f ********
+	logins_lock_file();
+
+	while(!wcfeof(f)) {
+		if((rr = wcfread(((char*)buf + ii*sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT), 1, sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT, f)) !=
+			sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT)
+		{
+			if((rr%sizeof(SSavedAuthSeq)) != 0) {
+				free(buf);
+				unlock_and_logins_io_error();
+			}
+		}
+		ii++;
+		buf = (SSavedAuthSeq*)realloc(buf, (ii+1)*sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT);
+	}
+
+	int changed = 0;
+	for(i = 0; i < ((ii-1)*SEQUENCE_READ_COUNT + (rr+1)/sizeof(SSavedAuthSeq)); i++)
+	{
+		if( buf[i].ExpireDate > tn && ((buf[i].ID[0] == id[0] && buf[i].ID[1] == id[1] && Uid == 0) ||
+			(buf[i].UniqID == Uid && id[0] == 0 && id[1] == 0)) )
+		{
+			if(wcfseek(f, i*sizeof(SSavedAuthSeq), SEEK_SET) < 0) {
+				free(buf);
+				unlock_and_logins_io_error();
+			}
+
+			// set time as sequence expired == free sequence
+			buf[i].ExpireDate = time(NULL) - 1;
+
+			if(wcfwrite(&buf[i], 1, sizeof(SSavedAuthSeq), f) != sizeof(SSavedAuthSeq)) {
+				free(buf);
+				unlock_and_logins_io_error();
+			}
+			changed = 1;
+			if(id != 0) break;
+		}
+	}
+
+	free(buf);
+
+	//******** unlock f ********
+	logins_unlock_file();
+
+	wcfclose(f);
+	return changed;
+}
+
+
+
+/* list authorization sequences by userId (=Uid)
+* return 1 if successfull otherwise 0 returned
+*/
+int GenerateListAuthSequence(char ***buflist, DWORD *sc, DWORD Uid)
+{
+	*buflist = NULL;
+	*sc = 0;
+	SSavedAuthSeq *buf;
+	WCFILE *f;
+	DWORD rr, i, cn=0, fpos;
+
+	if((f = wcfopen(F_AUTHSEQ, FILE_ACCESS_MODES_R)) == NULL) return 0;
+								
+	buf = (SSavedAuthSeq*)malloc(SEQUENCE_READ_COUNT*sizeof(SSavedAuthSeq));
+	if(!(*buflist = (char**)malloc(sizeof(char**)))) return 0;
+
+	/******** lock f ********/
+	logins_lock_file();
+								
+	do {
+		fpos = wcftell(f);
+		rr = wcfread(buf, 1, sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT, f);
+
+		if((rr%sizeof(SSavedAuthSeq)) != 0) {
+		/* read error */
+			free(buf);
+			for(i = 0; i < cn; i++)  free((*buflist)[i]);
+			free(buflist);
+			*buflist = NULL;
+			unlock_and_logins_io_error();
+		}
+																																								
+		rr = rr/sizeof(SSavedAuthSeq);
+		for(i = 0; i < rr; i++) {
+			if( Uid==0 || (buf[i].UniqID & (~SEQUENCE_IP_CHECK_DISABLED)) == Uid ){
+				*buflist = (char**)realloc(*buflist, (cn+1)*sizeof(char**));
+				(*buflist)[cn] = (char*)malloc(5*sizeof(DWORD) + 1);
+				memcpy(((char*)((*buflist)[cn])), &buf[i].ExpireDate, sizeof(DWORD));
+				memcpy(((char*)((*buflist)[cn]))+4, &buf[i].IP, sizeof(DWORD));
+				memcpy(((char*)((*buflist)[cn]))+8, &buf[i].ID[0], sizeof(DWORD));
+				memcpy(((char*)((*buflist)[cn]))+12, &buf[i].ID[1], sizeof(DWORD));
+				memcpy(((char*)((*buflist)[cn]))+16, &buf[i].UniqID, sizeof(DWORD));
+				cn++;
+			}
+		}
+	} while(rr == SEQUENCE_READ_COUNT);
+																																																																																	
+	free(buf);
+																																																																										
+	logins_unlock_file();
+	/********* unlock f *********/
+																																																																																				
+	wcfclose(f);
+	*sc = cn;
+	return 1;	
+}
+
+
+																																																																																																				
+/* check and update sequence 'id' with ttl - Time To Live
+ * return 1 if successfull otherwise -1 if not found and 0 if i/o error
+ */
+int CheckAndUpdateAuthSequence(DWORD id[2], DWORD IP, int ttl, SSavedAuthSeq *ui)
+{
+	SSavedAuthSeq *buf;
+	WCFILE *f;
+	DWORD rr, i, cn, fpos;
+	
+	if((f = wcfopen(F_AUTHSEQ, FILE_ACCESS_MODES_RW)) == NULL)
+		return 0;
+	buf = (SSavedAuthSeq*)malloc(sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT);
+
+	/******** lock f ********/
+	logins_lock_file();
+
+
+	while(!wcfeof(f)) {
+		fpos = wcftell(f);
+		rr = wcfread(buf, 1, sizeof(SSavedAuthSeq)*SEQUENCE_READ_COUNT, f);
+
+		if((rr%sizeof(SSavedAuthSeq)) != 0) {
+			/* read error */
+			free(buf);
+			unlock_and_logins_io_error();
+		}
+		cn = rr/sizeof(SSavedAuthSeq);
+
+		time_t tn = time(NULL);
+
+		for(i = 0; i < cn; i++) {
+			if( buf[i].ExpireDate > tn && buf[i].ID[0] == id[0] && buf[i].ID[1] == id[1] &&
+			( (buf[i].UniqID & SEQUENCE_IP_CHECK_DISABLED) != 0 || buf[i].IP == IP || ttl == 0 ) )
+			{
+				memcpy((void*)ui, &buf[i], sizeof(SSavedAuthSeq));
+
+				if(ttl){
+
+					if(wcfseek(f, fpos + i*sizeof(SSavedAuthSeq), SEEK_SET) != 0) {
+						free(buf);
+						unlock_and_logins_io_error();
+					}
+
+					buf[i].ExpireDate = time(NULL) + ttl;
+					if(!fCheckedWrite(&buf[i], sizeof(SSavedAuthSeq), f)) {
+						free(buf);
+						unlock_and_logins_io_error();
+					}
+				}
+
+				free(buf);
+				
+				logins_unlock_file();
+				/********* unlock f *********/
+				
+				wcfclose(f);
+				return 1;
+			}
+		}
+	}
+
+	logins_unlock_file();
+	/********* unlock f *********/
+
+	return -1;
+}
+
+/********************** CUserLogin **********************/
+CUserLogin::CUserLogin()
+{
+	uprof = NULL;
+	pui = NULL;
+	pfui = NULL;
+	LU.SIndex = 0xFFFFFFFF;
+	LU.right = DEFAULT_NOBODY_RIGHT;
+	LU.sec = DEFAULT_NOBODY_SECURITY_BYTE;
+	LU.sechdr = DEFAULT_NOBODY_HDR_SEC_BYTE;
+	LU.UniqID = 0;
+	LU.ID[0] = 0;
+	LU.ID[1] = 0;
+}
+
+CUserLogin::~CUserLogin()
+{
+	if(uprof != NULL)	delete uprof;
+	if(pui != NULL)		free(pui);
+	if(pfui != NULL)	free(pfui);
+}
+
+/* open user session and return 1 if successfull (all information will be stored
+ * to LU, otherwise return 0
+ */
+DWORD CUserLogin::OpenSession(char *uname, char *passw, SProfile_FullUserInfo *Fui, DWORD lIP, DWORD IPCheckD)
+{
+	int cr;
+	if(uprof == NULL) {
+		uprof = new CProfiles();
+		if(uprof->errnum != PROFILE_RETURN_ALLOK) {
+#if ENABLE_LOG >= 1
+			print2log("call to CProfiles::CProfiles failed at CUserLogin::OpenSession(), line %d", __LINE__);
+#endif
+			return 0;
+		}
+	}
+
+	if(pui == NULL) pui = (SProfile_UserInfo*)malloc(sizeof(SProfile_UserInfo));
+	if(pfui == NULL) pfui = (SProfile_FullUserInfo*)malloc(sizeof(SProfile_FullUserInfo));
+
+	if((cr = uprof->GetUserByName(uname, pui, pfui, &LU.SIndex)) == PROFILE_RETURN_ALLOK &&
+		strcmp(passw, pui->password) == 0)
+	{
+		/* prepare SUserInfo structure */
+		LU.right = pui->right;
+		LU.sec = pui->secur;
+		LU.sechdr = pui->secheader;
+		LU.UniqID = pui->UniqID;
+
+		/* modify SUPERUSER right */
+		if(LU.right & USERRIGHT_SUPERUSER) {
+			LU.right = LU.right | USERRIGHT_VIEW_MESSAGE | USERRIGHT_CLOSE_MESSAGE |
+				USERRIGHT_MODIFY_MESSAGE | USERRIGHT_CREATE_MESSAGE | USERRIGHT_CREATE_MESSAGE_THREAD |
+				USERRIGHT_OPEN_MESSAGE | USERRIGTH_ALLOW_HTML | USERRIGTH_PROFILE_MODIFY |
+				USERRIGTH_PROFILE_CREATE | USERRIGHT_POST_GLOBAL_ANNOUNCE | USERRIGHT_ALT_DISPLAY_NAME;
+		}
+
+		// fill sequence info
+		//SEQ.ID;					//	ID of session
+		//SEQ.Reserved;				//	Reserved place
+		//SEQ.ExpireDate;			//	Expiration date of the session
+		SEQ.UniqID = pui->UniqID;	//	UniqID of user
+		if(IPCheckD) SEQ.UniqID |= SEQUENCE_IP_CHECK_DISABLED;
+		SEQ.IP = lIP;				//	IP address of session
+		SEQ.SIndex = LU.SIndex;		//	Index in profindex file
+
+		/* open sequence for user */
+		if(OpenAuthSequence(SEQUENCE_LIVE_TIME, &SEQ) != 1) {
+			LU.SIndex = 0xFFFFFFFF;
+			LU.right = DEFAULT_NOBODY_RIGHT;
+			LU.sec = DEFAULT_NOBODY_SECURITY_BYTE;
+			LU.sechdr = DEFAULT_NOBODY_HDR_SEC_BYTE;
+			LU.UniqID = 0;
+			LU.ID[0] = 0;
+			LU.ID[1] = 0;
+			free(pui);
+			free(pfui);
+			pui = NULL;
+			pfui = NULL;
+#if ENABLE_LOG >= 1
+			print2log("Call to OpenAuthSequence failed at CUserLogin::OpenSession(), line %d", __LINE__);
+#endif
+			return 0;
+		}
+		else {
+			// save to LU
+			LU.ID[0] = SEQ.ID[0];
+			LU.ID[1] = SEQ.ID[1];
+			LU.ExpireDate = SEQ.ExpireDate;
+		}
+
+		// update IP and last login date
+		pui->lastIP = lIP;
+		pui->LoginDate = time(NULL);
+		if(uprof->SetUInfo(LU.SIndex, pui) != 1) {
+#if ENABLE_LOG >= 1
+			print2log("Call to CProfiles::SetUInfo failed at CUserLogin::OpenSession(), lined %d", __LINE__);
+#endif
+		}
+
+		// copy Full user info if requred
+		if(Fui != NULL) memcpy(Fui, pfui, sizeof(SProfile_FullUserInfo));
+		return 1;
+	}
+	else {
+#if ENABLE_LOG >= 1
+		if(cr == PROFILE_RETURN_DB_ERROR)
+			print2log("Call to CProfiles::GetUserByName failed at CUserLogin::OpenSession(), line %d", __LINE__);
+#endif
+		free(pui);
+		free(pfui);
+		pui = NULL;
+		pfui = NULL;
+		/* invalid username/password */
+		return 0;
+	}
+}
+
+/* check sequence seq for activity, set LU to this sequence and 
+ * return 1 if successfull, otherwise return 0
+ 
+ lIP == 0 - checking existing seq and Uid == seq.UniqID without updating (!!!)
+ Uid ==0 full checking with updating
+
+ */
+DWORD CUserLogin::CheckSession(DWORD seq[2], DWORD lIP, DWORD Uid)
+{
+	int seqttl=0;
+	if(lIP) seqttl = SEQUENCE_LIVE_TIME;
+
+
+	if(  Uid != 0  && lIP != 0) goto SessionErrorEnd;  //invalid calls
+
+
+	if(CheckAndUpdateAuthSequence(seq, lIP, seqttl, &SEQ) == 1) {
+		if(seqttl){
+
+			if(uprof == NULL) {
+				uprof = new CProfiles();
+				if(uprof->errnum != PROFILE_RETURN_ALLOK) {
+#if ENABLE_LOG >= 1
+					print2log("call to CProfiles::CProfiles failed at CUserLogin::CheckSession(), line %d", __LINE__);
+#endif
+					goto SessionError1;
+				}
+			}
+
+			if(pui == NULL) pui = (SProfile_UserInfo*)malloc(sizeof(SProfile_UserInfo));
+			if(pfui == NULL) pfui = (SProfile_FullUserInfo*)malloc(sizeof(SProfile_FullUserInfo));
+
+			if(uprof->GetUInfo(SEQ.SIndex, pui) != 1) {
+#if ENABLE_LOG >= 1
+				print2log("call to CProfiles::GetUInfo failed at CUserLogin::CheckSession(), line %d" \
+					" (maybe user has been deleted)", __LINE__);
+#endif
+				goto SessionError2;
+			}
+
+			// Update IP and last login date
+			pui->lastIP = lIP;
+			pui->LoginDate = time(NULL);
+			pui->RefreshCount++;
+
+			if(uprof->SetUInfo(SEQ.SIndex, pui) != 1) {
+#if ENABLE_LOG >= 1
+				print2log("Call to CProfiles::SetUInfo failed at CUserLogin::CheckSession(), lined %d", __LINE__);
+#endif
+				goto SessionError2;
+			}
+
+
+			if(uprof->GetFullInfo(pui->FullInfo_ID, pfui) != 1) {
+#if ENABLE_LOG >= 1
+				print2log("call to CProfiles::GetFullInfo() failed at CUserLogin::CheckSession(), line %d"
+					" (maybe user have been deleted)", __LINE__);
+#endif
+				goto SessionError2;
+			}
+
+
+			// Pui + Pfui is ok
+			// profile updated
+			// Load to LU
+
+			LU.ID[0] = SEQ.ID[0];
+			LU.ID[1] = SEQ.ID[1];
+			LU.SIndex = SEQ.SIndex;
+
+			LU.UniqID = (SEQ.UniqID & (~SEQUENCE_IP_CHECK_DISABLED));
+			LU.ExpireDate = SEQ.ExpireDate;
+
+			// LOAD REAL RIGHTS !!!
+			LU.right = pui->right;
+
+			// LOAD REAL SECURITY BYTES
+			LU.sechdr = pui->secheader;
+			LU.sec = pui->secur;
+
+			/* modify SUPERUSER right */
+			if(LU.right & USERRIGHT_SUPERUSER) {
+				LU.right = LU.right | USERRIGHT_VIEW_MESSAGE | USERRIGHT_CLOSE_MESSAGE |
+					USERRIGHT_MODIFY_MESSAGE | USERRIGHT_CREATE_MESSAGE | USERRIGHT_CREATE_MESSAGE_THREAD |
+					USERRIGHT_OPEN_MESSAGE | USERRIGTH_ALLOW_HTML | USERRIGTH_PROFILE_MODIFY |
+					USERRIGTH_PROFILE_CREATE | USERRIGHT_POST_GLOBAL_ANNOUNCE | USERRIGHT_ALT_DISPLAY_NAME;
+			}
+		}
+		else {
+			//smb wants check own Uid's session
+			if( Uid !=0 && (SEQ.UniqID & (~SEQUENCE_IP_CHECK_DISABLED)) != Uid ) return 0;
+		}
+
+		return 1;
+	}
+	// seqence cannot be found
+
+	goto SessionErrorEnd; 
+	
+SessionError2:
+
+	if(CloseAuthSequence(seq, 0) == 0) {}
+				
+	free(pui);
+	free(pfui);
+	pui = NULL;
+	pfui = NULL;
+
+SessionError1:
+
+	delete uprof;
+	uprof = NULL;
+
+SessionErrorEnd:
+
+	// init as no session
+	LU.SIndex = 0xFFFFFFFF;
+	LU.right = DEFAULT_NOBODY_RIGHT;
+	LU.sec = DEFAULT_NOBODY_SECURITY_BYTE;
+	LU.sechdr = DEFAULT_NOBODY_HDR_SEC_BYTE;
+	LU.UniqID = 0;
+	LU.ID[0] = 0;
+	LU.ID[1] = 0;
+
+	return 0;
+}
+
+/* close sequence seq
+ * return 1 if successfull, 0 otherwise
+ */
+DWORD CUserLogin::CloseSession(DWORD seq[2])
+{
+	if(CloseAuthSequence(seq, 0) == 1) {
+		LU.SIndex = 0xFFFFFFFF;
+		LU.right = DEFAULT_NOBODY_RIGHT;
+		LU.sec = DEFAULT_NOBODY_SECURITY_BYTE;
+		LU.sechdr = DEFAULT_NOBODY_HDR_SEC_BYTE;
+		LU.UniqID = 0;
+		LU.ID[0] = 0;
+		LU.ID[1] = 0;
+		if(pui != NULL) {
+			free(pui);
+			pui = NULL;
+		}
+		if(pfui != NULL) {
+			free(pfui);
+			pfui = NULL;
+		}
+		return 1;
+	}
+	return 0;
+}
+
+/* force closing session if user such user logged in.
+ * return 1 if successfull, 0 otherwise
+ */
+DWORD CUserLogin::ForceCloseSessionForUser(DWORD UniqID)
+{
+	DWORD x[2];
+	memset(&x, 0, 8);
+	if(CloseAuthSequence(x, UniqID) == 1) {
+		return 1;
+	}
+	return 0;
+}
+
+DWORD CUserLogin::ForceCloseSessionBySeq(DWORD seq[2])
+{
+
+	if(CloseAuthSequence(seq, 0) == 1) {
+		return 1;
+	}
+	return 0;
+}
+
+DWORD CUserLogin::GenerateListSessionForUser(char ***list, DWORD *scounter, DWORD Uniqid)
+{
+	if( GenerateListAuthSequence(list, scounter, Uniqid) == 1) return 1;
+	return 0;
+}	
blob - /dev/null
blob + 44b5c071bdeca3e57ca7e3a3c1a0859aca2095ac (mode 644)
--- /dev/null
+++ src/logins.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+                          login.cpp  -  log in/out support
+                             -------------------
+    begin                : Sun Apr 29 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef LOGINS_H_INCLUDED
+#define LOGINS_H_INCLUDED
+
+#include "basetypes.h"
+#include "profiles.h"
+
+#define SEQUENCE_READ_COUNT 1000
+#define SEQUENCE_LIVE_TIME USER_SESSION_LIVE_TIME
+
+struct SSavedAuthSeq {
+	DWORD ID[2];		//	ID of session (8 bytes)
+	DWORD UniqID;		//	UniqID of user
+						//	and also high bit of it is flag
+#define SEQUENCE_IP_CHECK_DISABLED	0xf0000000
+	DWORD IP;			//	IP address of session
+	DWORD SIndex;		//	Index in profindex file
+	time_t ExpireDate;	//	Expiration date of the session
+};
+
+struct SAuthUserSeq {
+	/* sequence number */
+	DWORD ID[2];
+	/* index of SProfile_UserInfo structure */
+	DWORD SIndex;
+	/* User specific parameters */
+	DWORD right;
+	/* uniq user ID */
+	DWORD UniqID;
+	// security level of message and header
+	BYTE sec;
+	BYTE sechdr;
+	// Expiration date of the session
+	time_t ExpireDate;
+};
+
+/* contain information about logged in user or
+ * about default user
+ */
+class CUserLogin {
+public:
+	CProfiles *uprof;
+	DWORD errnum;
+	SProfile_UserInfo *pui;
+	SProfile_FullUserInfo *pfui;
+	SAuthUserSeq LU;
+
+	SSavedAuthSeq SEQ;
+
+	/* constructor opens default session */
+	CUserLogin();
+	~CUserLogin();
+	DWORD OpenSession(char *uname, char *passw, SProfile_FullUserInfo *Fui, DWORD lIP, DWORD IPCheckD);
+	DWORD CheckSession(DWORD seq[2], DWORD lIP, DWORD Uid);
+	DWORD GetUserInfoStruct(DWORD seq[2]);
+	DWORD ForceCloseSessionForUser(DWORD UniqID);
+	DWORD ForceCloseSessionBySeq(DWORD seq[2]);
+	DWORD CloseSession(DWORD seq[2]);
+	DWORD GenerateListSessionForUser(char ***buflist, DWORD *sc, DWORD Uid);
+};
+
+#endif
+
blob - /dev/null
blob + 3027c063710293931d4b4ac55936a270606526da (mode 644)
--- /dev/null
+++ src/main.cpp
@@ -0,0 +1,5785 @@
+/***************************************************************************
+                          main.cpp  -  main module
+                             -------------------
+    begin                : Thu Mar 14 21:54:15 MSK 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+
+:set encoding=8bit-windows-1251
+:set termencoding=8bit-windows-1251
+:set termencoding=8bit-koi8-r
+ ***************************************************************************/
+
+//#ifdef HAVE_CONFIG_H
+//#include <config.h>
+//#endif
+
+#include "basetypes.h"
+#include "dbase.h"
+#include "error.h"
+#include "main.h"
+#include "messages.h"
+#include "speller.h"
+//#include "design.h"
+#include "security.h"
+#include "boardtags.h"
+#include "profiles.h"
+#include "logins.h"
+#include "searcher.h"
+#include "sendmail.h"
+#include "announces.h"
+#include "colornick.h"
+#include "activitylog.h"
+#include "statfs.h" 
+
+
+char *ConfTitle;
+
+char *MESSAGEHEAD_timetypes[4] = {
+	"ўрё(р)",		// coded as "1"
+	"фэ /фэхщ",		// coded as "2"
+	"эхфхыш(■)",	// coded as "3"
+	"ьхё Ў(хт)"		// coded as "4"
+};
+
+#if TOPICS_SYSTEM_SUPPORT
+char *Topics_List[TOPICS_COUNT] = {
+	"схч Єхь√",
+	"╠єЁчшыър",
+	"╧ЁюуЁрььшЁютрэшх",
+	"╨рсюЄр",
+	"╙ўхср",
+	"╬сёєцфхэшх",
+	"╩єяы■",
+	"─тшцюъ сюЁф√",
+	"╨рчтыхўхэш ",
+	"╧Ёюфрь",
+	"Temp",
+	"╙ёыєуш",
+	"Unix/Linux",
+	"Windows",
+	"╧Ёюсыхь√ ёхЄш",
+	"═ютюёЄш",
+	"├юыюёютрэшх",
+	"╧юЄхЁ эю/═рщфхэю"
+};
+int Topics_List_map[TOPICS_COUNT] = {
+	0, //"схч Єхь√",
+	4, //"╙ўхср",
+	3, //"╨рсюЄр",
+	1, //"╠єЁчшыър",
+	5, //"╬сёєцфхэшх",
+	15,//"═ютюёЄш"
+	8, //"╨рчтыхўхэш ",
+	7, //"─тшцюъ сюЁф√",
+	2, //"╧ЁюуЁрььшЁютрэшх",
+	6, //"╩єяы■",
+	9, //"╧Ёюфрь",
+	11,//"╙ёыєуш",
+	13,//"Windows",
+	12,//"Unix/Linux",
+	14,//"╧Ёюсыхь√ ёхЄш",
+	16,//"├юыюёютрэшх",
+	17,//"lost/found",
+	10,//"Temp",
+};
+#endif
+
+char *UserStatus_List[USER_STATUS_COUNT] = {
+	"═ютшўюъ",
+	"─єЁрўюъ",
+	"▌ъёяхЁЄ",
+	"├єЁє",
+	"╘ыєфхЁ"
+};
+
+char *UserRight_List[USERRIGHT_COUNT] = {
+	"SUPERUSER",
+	"VIEW_MESSAGE",
+	"MODIFY_MESSAGE",
+	"CLOSE_MESSAGE",
+	"OPEN_MESSAGE",
+	"CREATE_MESSAGE",
+	"CREATE_MESSAGE_THREAD",
+	"ALLOW_HTML",
+	"PROFILE_MODIFY",
+	"PROFILE_CREATE",
+	"ROLL_MESSAGE",
+	"UNROLL_MESSAGE",
+	"POST_GLOBAL_ANNOUNCE",
+	"ALT_DISPLAY_NAME"
+};
+
+int GlobalNewSession = 1;
+
+enum {
+	ACTION_POST,
+	ACTION_PREVIEW,
+	ACTION_EDIT
+};
+
+char* strget(char *par,const char *find, WORD maxl, char end, bool argparsing = true);
+
+int getAction(char* par)
+{
+#define JS_POST_FIELD "jpost"
+	int i = -1;
+	char* szActions[] = {
+		"post",
+		"preview",
+		"edit"
+	};
+	int cActions = sizeof(szActions) / sizeof(char*);
+	char* st = strget(par, JS_POST_FIELD"=", MAX_STRING, '&');
+	if(st && *st) {
+		for(i = 0; i < cActions; i++)
+			if(!strcmp(st, szActions[i]))
+				break;
+	} else {
+		char buf[MAX_STRING];
+		for(i = 0; i < cActions; i++)
+		{
+			sprintf(buf, "%s=", szActions[i]);
+			st = strget(par, buf, MAX_STRING, '&');
+			if(st)
+				break;
+		}
+	}
+	if(st)
+		free(st);
+	if(i < cActions)
+		return i;
+	return -1;
+}
+
+static void HttpRedirect(char *url)
+{
+	printf("Status: 302 Moved\n");
+	printf("Pragma: no-cache\n");
+	printf("Location: %s\n\n",url);
+}
+
+static void PrintBoardError(char *s1, char *s2, int code, DWORD msgid = 0)
+{
+	printf(DESIGN_GLOBAL_BOARD_MESSAGE, s1, s2);
+	if(code & HEADERSTRING_REFRESH_TO_MAIN_PAGE)
+		printf("%s", MESSAGEMAIN_browser_return);
+	if(code & HEADERSTRING_REFRESH_TO_THREAD && msgid != 0)
+		printf(MESSAGEMAIN_browser_to_thread, msgid);
+}
+
+static void PrintBanList  ()
+{
+	FILE *f;
+	int readed;
+	void *buf = malloc(MAX_HTML_FILE_SIZE);
+	if((f = fopen(F_BANNEDIP, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+	if((readed = fread(buf, 1, MAX_HTML_FILE_SIZE, f)) == 0) printhtmlerror();
+	printf(DESIGN_BAN_FORM);
+	if(fwrite(buf, 1, readed, stdout) != readed) printhtmlerror();
+	printf(DESIGN_BAN_FORM2);
+	free(buf);
+	fclose(f);
+
+}
+
+/* Prints post message form
+ */
+static void PrintMessageForm(SMessage *msg, char *body, DWORD s, int code, DWORD flags = 0)
+{
+	char tstr[2][100];
+
+	printf("<CENTER><FORM METHOD=POST NAME=\"postform\" onSubmit=\"return false;\" ACTION=\"%s?xpost=%lu\">",
+			MY_CGI_URL, s);
+
+	printf(DESIGN_POST_NEW_MESSAGE_TABLE "<TR><TD COLSPAN=2 ALIGN=CENTER><BIG>");
+	if(code & ACTION_BUTTON_EDIT) printf(MESSAGEMAIN_post_editmessage);
+	else if(code & ACTION_BUTTON_FAKEREPLY) printf("<A NAME=Reply>" MESSAGEMAIN_post_replymessage "</A>");
+	else printf(MESSAGEMAIN_post_newmessage);
+
+	printf("</BIG></TD></TR>");
+	printf("<TR><TD COLSPAN=2><HR ALIGN=CENTER WIDTH=80%% NOSHADE></TR>");
+
+	if(!(code & ACTION_BUTTON_EDIT)) {
+		if(ULogin.LU.ID[0] == 0) {
+			// print name/password form
+			printf("<TR><TD ALIGN=CENTER>%s &nbsp;"
+			"<INPUT TYPE=TEXT NAME=\"name\" SIZE=22 MAXLENGTH=%d VALUE=\"%s\"></TD>\n",
+				MESSAGEMAIN_post_you_name, AUTHOR_NAME_LENGTH - 1, msg->AuthorName);
+			// print password
+			printf("<TD ALIGN=LEFT>%s <INPUT TYPE=PASSWORD NAME=\"pswd\" SIZE=22"
+				" MAXLENGTH=%d VALUE=\"\">&nbsp;&nbsp;&nbsp;%s<INPUT TYPE=CHECKBOX NAME=\"lmi\"></TD></TR>\n",
+				MESSAGEMAIN_post_your_password, PROFILES_MAX_PASSWORD_LENGTH - 1, MESSAGEMAIN_post_login_me);
+		}
+		else {
+			// print name
+			printf("<TR><TD ALIGN=CENTER>%s </TD><TD><B>%s</B>&nbsp;&nbsp;&nbsp;<A HREF=\"%s?login=logoff\"><SMALL>[%s] </SMALL></A></TD></TR>\n",
+				MESSAGEMAIN_post_you_name, msg->AuthorName, MY_CGI_URL, MESSAGEHEAD_logoff);
+		}
+	}
+	else {
+		// print edit name and ip
+		if(ULogin.LU.ID[0] != 0 && (ULogin.LU.right & USERRIGHT_SUPERUSER) != 0) {
+			printf("<TR><TD ALIGN=CENTER>%s &nbsp;" \
+				"<INPUT TYPE=TEXT NAME=\"name\" SIZE=29 MAXLENGTH=%d VALUE=\"%s\"></TD>" \
+				"<TD>%s &nbsp;<INPUT TYPE=TEXT NAME=\"host\" SIZE=40 MAXLENGTH=%d" \
+				" VALUE=\"%s\"></TD></TR>", MESSAGEMAIN_post_you_name, AUTHOR_NAME_LENGTH - 1,
+				msg->AuthorName, MESSAGEMAIN_post_hostname, HOST_NAME_LENGTH - 1, msg->HostName);
+		}
+		
+	}
+
+#if TOPICS_SYSTEM_SUPPORT
+	// subject and topic
+	if(s == 0) {
+		printf("<TR><TD ALIGN=CENTER>%s ", MESSAGEMAIN_post_message_subject);
+		// Only for ROOT messages
+		printf("<SELECT NAME=\"topic\">");
+		for(DWORD i = 0; i < TOPICS_COUNT; i++) {
+			if(Topics_List_map[i] == msg->Topics) {
+				// define default choise
+				printf("<OPTION VALUE=\"%d\"" LISTBOX_SELECTED ">%s\n",
+					Topics_List_map[i], Topics_List[Topics_List_map[i]]);
+			}
+			else {
+				printf("<OPTION VALUE=\"%d\">%s\n", Topics_List_map[i], Topics_List[Topics_List_map[i]]);
+			}
+		}
+		printf("</SELECT></TD><TD>");
+	}
+	else {
+		printf("<TR><TD COLSPAN=2 ALIGN=CENTER>%s ", MESSAGEMAIN_post_message_subject);
+	}
+
+	printf("<INPUT TYPE=TEXT NAME=\"subject\" SIZE=%d MAXLENGTH=%d VALUE=\"%s\"></TD></TR>\n",
+		s? 88: 62, MESSAGE_HEADER_LENGTH - 1, msg->MessageHeader);
+
+#else
+	printf("<TR><TD COLSPAN=2 ALIGN=CENTER>%s ", MESSAGEMAIN_post_message_subject);
+	printf("<INPUT TYPE=TEXT NAME=\"subject\" SIZE=88 MAXLENGTH=%d VALUE=\"%s\"></TD></TR>\n",
+		MESSAGE_HEADER_LENGTH - 1, msg->MessageHeader);
+#endif	 		
+
+	printf("<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG>\n",
+		MESSAGEMAIN_post_message_body);
+				   
+	
+	printf("</TD></TD></TR><TR><TD COLSPAN=2 ALIGN=CENTER><TEXTAREA COLS=75 ROWS=12 NAME=\"body\" WRAP=VIRTUAL>%s</TEXTAREA></TD></TR>",
+		body);
+
+	tstr[0][0] = tstr[1][0] = 0;
+	if(flags & MSG_CHK_DISABLE_SMILE_CODES) strcpy(tstr[0], RADIO_CHECKED);
+	if(flags & MSG_CHK_DISABLE_WWWCONF_TAGS) strcpy(tstr[1], RADIO_CHECKED);
+	printf("<TR><TD COLSPAN=2 ALIGN=RIGHT class=cl>%s <INPUT TYPE=CHECKBOX NAME=\"dct\"%s class=cl></TD></TR>"
+	"<TR><TD COLSPAN=2 ALIGN=RIGHT class=cl>%s <INPUT TYPE=CHECKBOX NAME=\"dst\"%s class=cl></TD></TR>",
+		MESSAGEMAIN_post_disable_wwwconf_tags, tstr[1], MESSAGEMAIN_post_disable_smile_tags, tstr[0]);
+						  
+//	if(ULogin.LU.ID != 0) {
+		tstr[0][0] = 0;
+		if(flags & MSG_CHK_ENABLE_EMAIL_ACKNL) strcpy(tstr[0], RADIO_CHECKED);
+		printf("<TR><TD COLSPAN=2 ALIGN=RIGHT class=cl>%s<INPUT TYPE=CHECKBOX NAME=\"wen\"%s class=cl></TD></TR>",
+			 MESSAGEMAIN_post_reply_acknl, tstr[0]);
+//	}
+
+	printf("<TR><TD COLSPAN=2><HR ALIGN=CENTER WIDTH=80%% NOSHADE></TR><BR>");
+								 
+	printf("<TR><TD COLSPAN=2 ALIGN=CENTER>");
+
+	char onSubmitScript[] = 
+		"<script>\n"
+		"var cTries=0\n"
+		"function onSubmit(obj)\n"
+		"{\n"
+		"	var x=document.postform\n"
+		"	if (x.subject.value.length == 0) {\n"
+		"		alert(\"" MESSAGEMAIN_add_emptymsg_java "\");\n"
+		"		return false;\n"
+		"	}\n"
+		"	if (x.subject.value.length > 65530) {\n"
+		"		alert(\"" MESSAGEMAIN_add_tolong_java "\");\n"
+		"		return false;\n"
+		"	}\n"
+		"	if(obj)x.jpost.value = obj.name;\n"
+		"	if(document.all||document.getElementById) {\n"
+		"		for(i = 0; i < x.length; i++) {\n"
+		"			var tempobj = x.elements[i]\n"
+		"			if(\n"
+		"				tempobj.type &&\n"
+		"				(tempobj.type.toLowerCase() == \"submit\" || tempobj.type.toLowerCase() == \"reset\"))\n"
+		"			tempobj.disabled=true\n"
+		"		}\n"
+		"	}\n"
+		"	if(cTries++ == 0)\n"
+		"		x.submit();\n"
+		"	return false;\n"
+		"}\n"
+		"</script>\n";
+	printf("%s", onSubmitScript);
+
+	if(code & ACTION_BUTTON_EDIT) {
+		printf("\n<INPUT TYPE=SUBMIT NAME=\"edit\" onClick=\"onSubmit(this)\" VALUE=\"%s\">", MESSAGEMAIN_post_edit_message);
+	}
+	else {
+		if(code & ACTION_BUTTON_PREVIEW) {
+			printf("\n<INPUT TYPE=SUBMIT NAME=\"preview\" onClick=\"onSubmit(this)\" VALUE=\"%s\">&nbsp;",MESSAGEMAIN_post_preview_message);
+		}
+		if(code & ACTION_BUTTON_POST) {
+			printf("<INPUT TYPE=SUBMIT NAME=\"post\" onClick=\"onSubmit(this)\" VALUE=\"%s\">", MESSAGEMAIN_post_post_message);
+		}
+	}
+	printf("<INPUT TYPE=HIDDEN NAME=\"jpost\" VALUE=\"%s\">", "");
+
+	printf("</TD></TR></TABLE></FORM></CENTER><P>&nbsp;");
+}
+
+static void PrintLoginForm()
+{
+	printf("<P><FORM METHOD=POST ACTION=\"%s?login=action\">", MY_CGI_URL);
+	
+	printf(DESIGN_BEGIN_LOGIN_OPEN);
+
+	printf("<TR><TD ALIGN=RIGHT>%s</TD><TD><INPUT TYPE=TEXT NAME=\"mname\" SIZE=20 " \
+	       "MAXLENGTH=%d VALUE=\"%s\"></TD></TR><TR><TD ALIGN=RIGHT>%s</TD><TD>" \
+	       "<INPUT TYPE=PASSWORD NAME=\"mpswd\" SIZE=20 MAXLENGTH=30 VALUE=\"\"></TD></TR>",
+		MESSAGEMAIN_login_loginname, AUTHOR_NAME_LENGTH - 1,
+		FilterHTMLTags(cookie_name, 1000, 0), MESSAGEMAIN_login_password);
+
+	printf("<TR><TD COLSPAN=2><CENTER><INPUT TYPE=CHECKBOX NAME=\"ipoff\" VALUE=1>" \
+		MESSAGEMAIN_login_ipcheck "</CENTER></TD></TR>");
+	
+	printf("<P><TR><TD COLSPAN=2 ALIGN=CENTER><INPUT TYPE=SUBMIT VALUE=\"Enter\"></TD></TR>" DESIGN_END_LOGIN_CLOSE "</FORM>");
+
+	printf(MESSAGEMAIN_login_lostpassw);
+}
+
+static void PrintPrivateMessageForm(char *name, char *body)
+{
+	printf("<CENTER><FORM METHOD=POST ACTION=\"%s?persmsgpost\"><P>&nbsp;<P>", MY_CGI_URL);
+
+	printf(DESIGN_POST_NEW_MESSAGE_TABLE "<TH COLSPAN=2><BIG>" MESSAGEMAIN_privatemsg_send_msg_hdr
+		"</BIG></TR><TR><TD COLSPAN=2><HR ALIGN=CENTER WIDTH=80%% NOSHADE></TR>");
+	printf("<TR><TH ALIGN=RIGHT>%s </TH><TD>"
+		"<INPUT TYPE=TEXT NAME=\"name\" SIZE=30 MAXLENGTH=%d VALUE=\"%s\"></TD></TR>"
+		"<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG>", 
+		MESSAGEMAIN_privatemsg_send_msg_usr, PROFILES_MAX_USERNAME_LENGTH - 1,
+		name, MESSAGEMAIN_privatemsg_send_msg_bdy);
+
+	printf("<BR><TEXTAREA COLS=50 ROWS=7 NAME=\"body\" WRAP=VIRTUAL>%s</TEXTAREA></TD></TR>", body);
+
+	printf("<TR><TD COLSPAN=2><HR ALIGN=CENTER WIDTH=80%% NOSHADE></TR><BR><TR><TD COLSPAN=2 ALIGN=CENTER>"
+		"<INPUT TYPE=SUBMIT NAME=\"Post\" VALUE=\"%s\">&nbsp;<INPUT TYPE=SUBMIT NAME=\"Post\" VALUE=\"%s\"></TD></TR></TABLE></FORM></CENTER>",
+		MESSAGEMAIN_privatemsg_prev_msg_btn, MESSAGEMAIN_privatemsg_send_msg_btn);
+}
+
+static void PrintAnnounceForm(char *body, int ChangeAnn = 0)
+{
+	printf("<CENTER><FORM METHOD=POST ACTION=\"%s?globann=post\"><P>&nbsp;<P>", MY_CGI_URL);
+
+	printf(DESIGN_POST_NEW_MESSAGE_TABLE "<TH COLSPAN=2><BIG>%s</BIG></TR><TR><TD COLSPAN=2><HR ALIGN=CENTER WIDTH=80%% NOSHADE></TR>",
+		ChangeAnn ? MESSAGEMAIN_globann_upd_ann_hdr : MESSAGEMAIN_globann_send_ann_hdr);
+
+	printf("<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG><BR>"
+		"<TEXTAREA COLS=50 ROWS=7 NAME=\"body\" WRAP=VIRTUAL>%s</TEXTAREA></TD></TR>",
+			MESSAGEMAIN_globann_send_ann_body, body);
+
+	if(ChangeAnn) printf("<TR><TD COLSPAN=2><CENTER><INPUT TYPE=CHECKBOX NAME=\"refid\" VALUE=1>" \
+		MESSAGEMAIN_globann_upd_ann_id "</CENTER></TD></TR>");
+	printf("<TR><TD COLSPAN=2><HR ALIGN=CENTER WIDTH=80%% NOSHADE></TR><BR><TR><TD COLSPAN=2 ALIGN=CENTER>");
+	if(ChangeAnn) printf("<INPUT TYPE=HIDDEN NAME=\"cgann\" VALUE=\"%d\">", ChangeAnn);
+	printf("<INPUT TYPE=SUBMIT NAME=\"Post\" VALUE=\"%s\"><INPUT TYPE=SUBMIT NAME=\"Post\" VALUE=\"%s\"></TD></TR></TABLE></FORM></CENTER>",
+		MESSAGEMAIN_globann_prev_ann_btn, MESSAGEMAIN_globann_send_ann_btn);
+}
+
+static void PrintLostPasswordForm()
+{
+	printf("<P><FORM METHOD=POST ACTION=\"%s?login=lostpasswaction\">", MY_CGI_URL);
+
+	printf(DESIGN_BEGIN_LOSTPASSW_OPEN);
+
+	printf("<TR><TD ALIGN=RIGHT>%s</TD><TD><INPUT TYPE=TEXT NAME=\"mname\" SIZE=20 MAXLENGTH=%d "
+		"VALUE=\"%s\"></TD></TR><TR><TD ALIGN=RIGHT>%s</TD><TD><INPUT TYPE=TEXT NAME=\"memail\" SIZE=20 "
+		"MAXLENGTH=%d VALUE=\"\"></TD></TR>", MESSAGEMAIN_lostpassw_loginname, AUTHOR_NAME_LENGTH - 1,
+		FilterHTMLTags(cookie_name, 1000, 0), MESSAGEMAIN_lostpassw_email, PROFILES_FULL_USERINFO_MAX_EMAIL - 1);
+
+	printf("<P><TR><TD COLSPAN=2 ALIGN=CENTER><INPUT TYPE=SUBMIT VALUE=\"" MESSAGEMAIN_lostpassw_getpassw "\"><CENTER></TD></TR>" DESIGN_END_LOSTPASSW_CLOSE "</FORM>");
+}
+
+/* print configuration form */
+static void PrintConfig()	
+{
+	char str1[20], str2[20], str3[20], str4[20], str5[20], str6[20], str7[20], str8[20], str9[20];
+	char strm[10][20];
+	int i;
+
+	printf("<TABLE align=center width=100%%><tr><td><FORM METHOD=POST ACTION=\"%s?configure=action\" name=\"configure\">",
+		MY_CGI_URL);
+	
+	printf("<CENTER><P><B>%s</B><BR><P>", MESSAGEHEAD_configure);
+	
+	printf("<P><B>%s</B><BR><P>", MESSAGEHEAD_configure_showmsgs);
+
+	str1[0] = str2[0] = str3[0] = str4[0] = str5[0] = 0;
+	if(currentlsel == 1) strcpy(str1, RADIO_CHECKED);
+
+	switch(currenttt) {
+	case 1:
+		strcpy(str2, LISTBOX_SELECTED);
+		break;
+	case 2:
+		strcpy(str3, LISTBOX_SELECTED);
+		break;
+	case 3:
+		strcpy(str4, LISTBOX_SELECTED);
+		break;
+	case 4:
+		strcpy(str5, LISTBOX_SELECTED);
+		break;
+	}
+	printf("<INPUT TYPE=RADIO NAME=lsel VALUE=1%s>%s" \
+		"<INPUT TYPE=TEXT NAME=\"tv\" SIZE=2 VALUE=%d><SELECT NAME=\"tt\">" \
+		"<OPTION VALUE=\"1\"%s>%s<OPTION VALUE=\"2\"%s>%s<OPTION VALUE=\"3\"%s>" \
+		"%s<OPTION VALUE=\"4\"%s>%s</SELECT><BR>",
+		str1, MESSAGEHEAD_configure_msgslast, currenttv,
+		str2, MESSAGEHEAD_timetypes[0], str3, MESSAGEHEAD_timetypes[1], str4,
+		MESSAGEHEAD_timetypes[2], str5, MESSAGEHEAD_timetypes[3]
+	);
+
+	str1[0] = str2[0] = str3[0] = str4[0] = str5[0] = 0;
+	if(currentlsel == 2) strcpy(str1, RADIO_CHECKED);
+
+	switch(currentss) {
+	case 1:
+		strcpy(str2, LISTBOX_SELECTED);
+		break;
+	case 2:
+		strcpy(str3, LISTBOX_SELECTED);
+		break;
+	case 3:
+		strcpy(str4, LISTBOX_SELECTED);
+		break;
+	case 4:
+		strcpy(str5, LISTBOX_SELECTED);
+		break;
+	}
+
+	printf("<INPUT TYPE=RADIO NAME=lsel VALUE=2%s>%s<INPUT TYPE=TEXT NAME=\"tc\" SIZE=3 VALUE=%d>"
+		"%s<P>%s<SELECT NAME=\"ss\"><OPTION VALUE=\"2\"%s>%s<OPTION VALUE=\"3\"%s>%s<OPTION VALUE=\"4\"%s>"
+		"%s</SELECT>",
+		str1, MESSAGEHEAD_configure_lastnum, currenttc, MESSAGEHEAD_configure_lastnum2,
+		MESSAGEHEAD_configure_showstyle, str3,
+		MESSAGEHEAD_configure_showhronbackward, str4,
+		MESSAGEHEAD_configure_showhronwothreads, str5,
+		MESSAGEHEAD_configure_showhrononlyheaders);
+
+	printf("<BR><BR>┬Ёхьхээющ яю ё: <SELECT NAME=\"tz\">");
+	for(i = -12; i <= 12; i++)
+		printf("<OPTION VALUE=\"%d\"%s>Timezone GMT%s%02d", i,
+		(i == currenttz) ? LISTBOX_SELECTED : "", (i>=0) ? "+" : "-", (i>0)? i : -i);
+	printf("</SELECT><BR>");
+
+
+#if TOPICS_SYSTEM_SUPPORT
+	// use str4 for temporaty buffer
+	printf("<BR><P><TABLE BORDER=1 CELLSPACING=0 CELLPADDING=6 BGCOLOR=#BBAAAA>\
+<TR><TD ALIGN=CENTER>" DESIGN_CONFIGURE_CHECKALL "</TD></TR><TR><TD ALIGN=RIGHT>");
+	for(DWORD i = 0; i < TOPICS_COUNT; i++)
+	{
+		if(currenttopics & (1<<Topics_List_map[i]))
+			strcpy(str4, RADIO_CHECKED);
+		else str4[0] = 0;
+		printf("%s <INPUT TYPE=CHECKBOX NAME=\"topic%d\"%s><br>\n",
+			Topics_List[Topics_List_map[i]], Topics_List_map[i], str4);
+	}
+	printf("</TD></TR></TABLE>");
+#endif
+
+	if((currentdsm & 0x01) != 0) strcpy(str3, RADIO_CHECKED);
+	else str3[0] = 0;
+	if((currentdsm & 0x02) != 0) strcpy(str4, RADIO_CHECKED);
+	else str4[0] = 0;
+	if((currentdsm & 0x04) != 0) strcpy(str5, RADIO_CHECKED);
+	else str5[0] = 0;
+	if((currentdsm & 0x08) != 0) strcpy(str2, RADIO_CHECKED);
+	else str2[0] = 0;
+	if((currentdsm & 0x10) != 0) strcpy(str1, RADIO_CHECKED);
+	else str1[0] = 0;
+	if((currentdsm & 0x20) != 0) strcpy(str6, RADIO_CHECKED);
+	else str6[0] = 0;
+	if((currentdsm & 0x40) != 0) strcpy(str7, RADIO_CHECKED);
+	else str7[0] = 0;
+	if((currentdsm & 0x80) != 0) strcpy(str8, RADIO_CHECKED);
+	else str8[0] = 0;
+	if((currentdsm & 0x100) != 0) strcpy(str9, RADIO_CHECKED);
+	else str9[0] = 0;
+
+	printf("<TABLE><TR><TD ALIGN=RIGHT>%s<INPUT TYPE=CHECKBOX NAME=\"dsm\" VALUE=1%s>",
+		MESSAGEHEAD_configure_disablesmiles, str3);
+	printf("<BR>%s<INPUT TYPE=CHECKBOX NAME=\"dup\" VALUE=1%s>",
+		MESSAGEHEAD_configure_disableuppic, str4);
+	printf("<BR>%s<INPUT TYPE=CHECKBOX NAME=\"dul\" VALUE=1%s>",
+		MESSAGEHEAD_configure_disable2links, str5);
+	printf("<BR>%s<INPUT TYPE=CHECKBOX NAME=\"onh\" VALUE=1%s>",
+		MESSAGEHEAD_configure_ownpostshighlight, str2);
+	printf("<BR>%s<INPUT TYPE=CHECKBOX NAME=\"host\" VALUE=1%s>",
+		MESSAGEHEAD_configure_showhostnames, str6);
+	printf("<BR>%s<INPUT TYPE=CHECKBOX NAME=\"nalt\" VALUE=1%s>",
+		MESSAGEHEAD_configure_showaltnames, str7);
+	printf("<BR>%s<INPUT TYPE=CHECKBOX NAME=\"dsig\" VALUE=1%s>",
+		MESSAGEHEAD_configure_showsign, str8);
+	printf("<BR>%s<INPUT TYPE=CHECKBOX NAME=\"shrp\" VALUE=1%s>",
+		MESSAGEHEAD_configure_showreplyform, str9);
+#if ALLOW_MARK_NEW_MESSAGES == 2
+	printf("<BR>%s<INPUT TYPE=CHECKBOX NAME=\"plu\" VALUE=1%s>",
+		MESSAGEHEAD_configure_plus_is_href, str1);
+#endif
+	printf("</TD></TR></TABLE>");
+
+	if(ULogin.LU.ID[0] && (ULogin.pui->Flags & PROFILES_FLAG_VIEW_SETTINGS) )
+			printf("<P>" MESSAGEHEAD_configure_saving_to_profile "<BR>");
+	else printf("<P>" MESSAGEHEAD_configure_saving_to_browser "<BR>");
+	if(ULogin.LU.ID[0]) printf(MESSAGEHEAD_configure_view_saving "<BR>");
+	
+	printf("<P><INPUT TYPE=SUBMIT VALUE=\"%s\"></CENTER></FORM></form></td></tr></table>",
+		MESSAGEHEAD_configure_applysettings);
+	
+}
+
+void PrintTopString(DWORD c, DWORD ind, DWORD ret)
+{
+	/* print init code */
+	printf(DESIGN_COMMAND_TABLE_BEGIN);
+	
+	/* print messages */
+	int g = 0;
+
+	if(c & HEADERSTRING_ENABLE_TO_MESSAGE) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"#%ld\" STYLE=\"text-decoration:underline;\">%s</A>", ret, MESSAGEHEAD_to_message);
+		g = 1;
+	}
+
+	if((c & HEADERSTRING_ENABLE_TO_MESSAGE) || (c & HEADERSTRING_ENABLE_REPLY_LINK)) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		if((c & HEADERSTRING_ENABLE_REPLY_LINK))
+			printf("<A HREF=\"%s?form=%ld\" STYLE=\"text-decoration:underline;\">%s</A>",
+				MY_CGI_URL, ret, MESSAGEMAIN_post_replymessage);
+		else printf("<A HREF=\"#Reply\" STYLE=\"text-decoration:underline;\">%s</A>",
+				MESSAGEMAIN_post_replymessage);
+		g = 1;
+	}
+
+	if(c & HEADERSTRING_RETURN_TO_MAIN_PAGE) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		if(ind == MAINPAGE_INDEX || ind == 0) printf("<A HREF=\"%s?index\" STYLE=\"text-decoration:underline;\">%s</A>",
+			MY_CGI_URL, MESSAGEHEAD_return_to_main_page);
+		else printf("<A HREF=\"%s?index#%ld\"><font color=\"#F00F0F\" STYLE=\"text-decoration:underline;\">%s</font></A>",
+			MY_CGI_URL, ind, MESSAGEHEAD_return_to_main_page);
+		g = 1;
+	}
+	
+	if(c & HEADERSTRING_POST_NEW_MESSAGE) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"%s?form\" STYLE=\"text-decoration:underline;\">%s</A>", MY_CGI_URL, MESSAGEHEAD_post_new_message);
+		g = 1;
+	}
+
+	if((c & HEADERSTRING_DISABLE_SEARCH) == 0) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"%s?search=form\" STYLE=\"text-decoration:underline;\">%s</A>", MY_CGI_URL, MESSAGEHEAD_search);
+		g = 1;
+	}
+	
+	if(c & HEADERSTRING_CONFIGURE) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"%s?configure=form\" STYLE=\"text-decoration:underline;\">%s</A>", MY_CGI_URL, MESSAGEHEAD_configure);
+		g = 1;
+	}
+
+	if(c & HEADERSTRING_ENABLE_RESETNEW) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"%s?resetnew\" STYLE=\"text-decoration:underline;\">%s</A>", MY_CGI_URL, MESSAGEHEAD_resetnew);
+		g = 1;
+	}
+
+	if((c & HEADERSTRING_DISABLE_REGISTER) == 0) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		if(ULogin.LU.ID[0] != 0)
+			printf("<A HREF=\"%s?register=form\" STYLE=\"text-decoration:underline;\">%s</A>", MY_CGI_URL, MESSAGEHEAD_registerprf);
+		else
+			printf("<A HREF=\"%s?register=form\" STYLE=\"text-decoration:underline;\">%s</A>", MY_CGI_URL, MESSAGEHEAD_register);
+		g = 1;
+	}
+
+	if(c & HEADERSTRING_REG_USER_LIST) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"%s?userlist\" STYLE=\"text-decoration:underline;\">%s</A>", MY_CGI_URL, MESSAGEHEAD_userlist);
+		g = 1;
+	}
+	
+	if( (ULogin.LU.right & USERRIGHT_SUPERUSER) != 0  && HEADERSTRING_REG_USER_LIST) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"%s?banlist\" STYLE=\"text-decoration:underline;\">%s</a>", MY_CGI_URL, MESSAGEHEAD_banlist);
+	}
+
+	if((ULogin.LU.ID[0] == 0) && ((c & HEADERSTRING_DISABLE_LOGIN) == 0)) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"%s?login=form\" STYLE=\"text-decoration:underline;\">%s</A>", MY_CGI_URL, MESSAGEHEAD_login);
+		g = 1;
+	}
+
+	if((c & HEADERSTRING_DISABLE_FAQHELP) == 0) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"rules.html\" STYLE=\"text-decoration:underline;\">" MESSAGEHEAD_help_showhelp "</A>");
+		g = 1;
+	}
+
+#if USER_FAVOURITES_SUPPORT
+	if(ULogin.LU.ID[0] != 0 && (c & HEADERSTRING_DISABLE_FAVOURITES) == 0) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"%s?favs\" STYLE=\"text-decoration:underline;\">%s</A>",
+				MY_CGI_URL, MESSAGEHEAD_favourites);
+		g = 1;
+	}
+#endif
+
+	if(ULogin.LU.ID[0] != 0 && (c & HEADERSTRING_DISABLE_PRIVATEMSG) == 0) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		if(ULogin.pui->persmescnt - ULogin.pui->readpersmescnt > 0)
+			printf("<A HREF=\"%s?persmsg\" STYLE=\"text-decoration:underline;\"><FONT COLOR=RED><BOLD>%s(%d)</BOLD></FONT></A>",
+				MY_CGI_URL, MESSAGEHEAD_personalmsg, ULogin.pui->persmescnt - ULogin.pui->readpersmescnt);
+		else
+			printf("<A HREF=\"%s?persmsg\" STYLE=\"text-decoration:underline;\">%s</A>", MY_CGI_URL, MESSAGEHEAD_personalmsg);
+		g = 1;
+	}
+
+	if((ULogin.LU.right & USERRIGHT_POST_GLOBAL_ANNOUNCE) != 0 && (c & HEADERSTRING_POST_NEW_MESSAGE) != 0) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"%s?globann=form\" STYLE=\"text-decoration:underline;\">%s</A>", MY_CGI_URL, MESSAGEHEAD_makeannounce);
+		g = 1;
+	}
+	
+	if((ULogin.LU.ID[0] != 0) && ((c & HEADERSTRING_DISABLE_LOGOFF) == 0)) {
+		if(g) printf(DESIGN_BUTTONS_DIVIDER);
+		printf("<A HREF=\"%s?login=logoff\" STYLE=\"text-decoration:underline;\">%s</A>", MY_CGI_URL, MESSAGEHEAD_logoff);
+		g = 1;
+	}
+	
+	printf("</TD></TR></TABLE>");
+}
+
+void PrintTopStaticLinks(DWORD c)
+{
+	//print stable links on index page
+	if ((c & HEADERSTRING_REG_USER_LIST) != 0 && (currentdsm & 4) == 0) {
+		//printf("<TR><TD class=cs align=center>");
+		printf(DESIGN_COMMAND_TABLE_BEGIN);
+		printf("<!--<A HREF=\"/dev/\" target=_blank STYLE=\"text-decoration:underline;\"><nobr>%s</nobr></A>", "Programming Board-->");
+		//gray space after top links
+		printf("<TR><TD class=cl>&nbsp;</TD></TR>");
+		printf("</TD></TR></TABLE>"); 
+	} 
+
+}
+
+/* print HTML header of file, header placed in topbanner.html */
+void PrintHTMLHeader(DWORD code, DWORD curind, DWORD retind = 0)
+{
+	if(!HPrinted) {
+		printf("Content-type: text/html\n");
+		HPrinted = 1; // header have been printed
+	}
+
+
+	if((code & HEADERSTRING_NO_CACHE_THIS) != 0) printf("Pragma: no-cache\n");
+
+	printf("Set-Cookie: " COOKIE_NAME_STRING "name=%s|ed=%d|lsel=%d|tc=%d|tt=%d|tv=%d|ss=%d|" \
+		"lm=%ld|fm=%ld|lt=%ld|ft=%ld|dsm=%d|seq=%08x%08x|topics=%d|lann=%d|tovr=%d|tz=%d&;" \
+		" expires=" COOKIE_EXPIRATION_DATE "path=" COOKIE_SERVER_PATH
+		"\nSet-Cookie: " COOKIE_SESSION_NAME "on&; path=" COOKIE_SERVER_PATH "\n\n", 
+		 CodeHttpString(cookie_name, 0), cookie_lastenter, cookie_lsel, cookie_tc, cookie_tt, cookie_tv,
+		 cookie_ss, currentlm, currentfm, currentlt, currentft, cookie_dsm, ULogin.LU.ID[0], ULogin.LU.ID[1],
+		cookie_topics, currentlann, topicsoverride,cookie_tz);
+
+	printf(HTML_START);
+
+	if((code & HEADERSTRING_REDIRECT_NOW)) {
+	        printf("<meta http-equiv=\"Refresh\" content=\"0; url=%s?index\"></head></html>", MY_CGI_URL);
+		return;
+	}
+
+	if(code & HEADERSTRING_REFRESH_TO_MAIN_PAGE) {
+		if(curind == MAINPAGE_INDEX || curind == 0)
+			printf("<meta http-equiv=\"Refresh\" content=\"%d; url=%s?index\">",
+			AUTO_REFRESH_TIME, MY_CGI_URL);
+		else
+			printf("<meta http-equiv=\"Refresh\" content=\"%d; url=%s?index#%ld\">",
+			AUTO_REFRESH_TIME, MY_CGI_URL, curind);
+	}
+
+	// print output encoding (charset)
+	printf(TEXT_ENCODING_HEADER);
+
+	// print title
+#if STABLE_TITLE == 0
+	printf("<title>%s</title>", ConfTitle);
+#else
+	printf("<title>%s</title>", TITLE_StaticTitle);
+#endif
+
+
+	printf(TEXT_STYLE_HEADER);
+	
+	// print header of board
+#if USE_TEXT_TOPBANNER
+	// print constant expressions
+	printf(TEXT_TOPBANNER_HEADER);
+	
+	if(curind == MAINPAGE_INDEX && (currentdsm & 2) == 0) printf(TEXT_TOPBANNER_MAP);
+#else
+	// print from TOPBANNER file
+	{
+		FILE *f;
+		DWORD readed;
+		void *buf = malloc(MAX_HTML_FILE_SIZE);
+		if((f = fopen(F_TOPBANNER,FILE_ACCESS_MODES_R)) == NULL)
+			printhtmlerrorat(LOG_UNABLETOLOCATEFILE, F_TOPBANNER);
+		if((readed = fread(buf, 1, MAX_HTML_FILE_SIZE, f)) == 0)
+			printhtmlerrorat(LOG_UNABLETOLOCATEFILE, F_TOPBANNER);
+		if(fwrite(buf, 1, readed, stdout) != readed) printhtmlerror();
+		free(buf);
+		fclose(f);
+	}
+#endif
+
+	if((HEADERSTRING_DISABLE_ALL & code) == 0) {
+		/* print top string (navigation) */
+		PrintTopString(code, curind, retind);
+		PrintTopStaticLinks (code);
+	}
+}
+
+/* print bottom lines from file (banners, etc.) */
+void PrintBottomLines(DWORD code, DWORD curind, DWORD retind = 0)
+{
+	// gap between end of board and bottom header
+	printf(DESIGN_INDEX_WELCOME_CLOSE);
+
+/*	if(((HEADERSTRING_DISABLE_ALL & code) == 0) ) {
+		PrintTopString(code, curind, retind);
+	}*/
+
+
+#if USE_TEXT_BOTTOMBANNER
+	if(curind == MAINPAGE_INDEX && (currentdsm & 2) == 0) 
+		printf(TEXT_BOTTOMBANNER);
+	else 
+		printf(TEXT_BOTTOMBANNER_SHORT);
+#else
+	{
+		FILE *f;
+		void *buf;
+		DWORD readed;
+		if((buf = malloc(MAX_HTML_FILE_SIZE)) == NULL)
+			printhtmlerrorat(LOG_FATAL_NOMEMORY, MAX_HTML_FILE_SIZE);
+		if((f = fopen(F_BOTTOMBANNER,FILE_ACCESS_MODES_R)) == NULL)
+			printhtmlerrorat(LOG_UNABLETOLOCATEFILE, F_BOTTOMBANNER);
+		if((readed = fread(buf, 1, MAX_HTML_FILE_SIZE, f)) == 0)
+			printhtmlerrorat(LOG_UNABLETOLOCATEFILE, F_BOTTOMBANNER);
+		if(fwrite(buf, 1, readed, stdout) != readed) printhtmlerror();
+		fclose(f);
+		free(buf);
+	}
+#endif
+}
+
+/* print moderation toolbar and keys
+ * 
+ */
+int PrintAdminToolbar(DWORD root, int mflag, DWORD UID)
+{
+	DWORD fl = 0;	// store bit mask for keys
+
+	/* allow to superuser or author */
+	if((ULogin.LU.right & USERRIGHT_SUPERUSER) || (ULogin.LU.ID[0] != 0 &&
+		ULogin.LU.UniqID == UID)) {
+
+		if(((mflag & MESSAGE_IS_CLOSED) == 0) && (ULogin.LU.right & USERRIGHT_CLOSE_MESSAGE))
+			fl = fl | 0x0001;
+
+		if((mflag & MESSAGE_IS_CLOSED) && (ULogin.LU.right & USERRIGHT_OPEN_MESSAGE))
+			fl = fl | 0x0002;
+
+		if(ULogin.LU.right & USERRIGHT_MODIFY_MESSAGE)
+			fl = fl | 0x0004;
+	}
+
+	/* allow only to superuser */
+	if(ULogin.LU.right & USERRIGHT_SUPERUSER) {
+		
+		fl = fl | 0x0080; /* delete */
+
+		if((mflag & MESSAGE_IS_INVISIBLE) == 0)
+			fl = fl | 0x0008;
+		
+		if(mflag & MESSAGE_IS_INVISIBLE)
+			fl = fl | 0x0010;
+		
+		if((mflag & MESSAGE_COLLAPSED_THREAD) == 0)
+			fl = fl | 0x0020;
+		
+		if(mflag & MESSAGE_COLLAPSED_THREAD)
+			fl = fl | 0x0040;
+	}
+
+	int g = 0;
+	if(fl) {
+		/* print administration table */
+		printf("<BR><CENTER><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=1"
+			"BGCOLOR=\"#eeeeee\"><TR><TD ALIGN=CENTER>[ <SMALL>");
+		
+		/* close thread */
+		if(fl & 0x0001) {
+			printf("<A HREF=\"%s?close=%ld\"><font color=\"#AF0000\">%s</font></A>",
+				MY_CGI_URL, root, MESSAGEMAIN_moderate_close_thread);
+			g = 1;
+		}
+
+		/* open thread */
+		if(fl & 0x0002) {
+			if(g) printf(DESIGN_BUTTONS_DIVIDER);
+			printf("<A HREF=\"%s?unclose=%ld\"><font color=\"#AF0000\">%s</font></A>",
+				MY_CGI_URL, root, MESSAGEMAIN_moderate_unclose_thread);
+			g = 1;
+		}
+		
+		// change message 
+		if(fl & 0x0004) {
+			if(g) printf(DESIGN_BUTTONS_DIVIDER);
+			printf("<A HREF=\"%s?changemsg=%ld\"><font color=\"#AF0000\">%s</font></A>",
+				MY_CGI_URL, root, MESSAGEMAIN_moderate_change_message);
+		}
+
+		/* collapse thread */
+		if(fl & 0x0020) {
+			if(g) printf(DESIGN_BUTTONS_DIVIDER);
+			printf("<A HREF=\"%s?roll=%ld\"><font color=\"#AF0000\">%s</font></A>",
+				MY_CGI_URL, root, MESSAGEMAIN_moderate_roll);
+		}
+			
+		/* uncollapse thread */
+		if(fl & 0x0040) {
+			if(g) printf(DESIGN_BUTTONS_DIVIDER);
+			printf("<A HREF=\"%s?roll=%ld\"><font color=\"#AF0000\">%s</font></A>",
+				MY_CGI_URL, root, MESSAGEMAIN_moderate_unroll);
+		}
+
+		/* hide thread */
+		if(fl & 0x0008) {
+			if(g) printf(DESIGN_BUTTONS_DIVIDER);
+			printf("<A HREF=\"%s?hide=%ld\"><font color=\"#AF0000\">%s</font></A>",
+				MY_CGI_URL, root, MESSAGEMAIN_moderate_hide_thread);
+			g = 1;
+		}
+		
+		/* unhide thread */
+		if(fl & 0x0010) {
+			if(g) printf(DESIGN_BUTTONS_DIVIDER);
+			printf("<A HREF=\"%s?unhide=%ld\"><font color=\"#AF0000\">%s</font></A>",
+				MY_CGI_URL, root, MESSAGEMAIN_moderate_unhide_thread);
+			g =1;
+		}
+
+		/* delete thread */
+		if(fl & 0x0080) {
+			if(g) printf(DESIGN_BUTTONS_DIVIDER);
+			printf("<A HREF=\"%s?delmsg=%d\"><font color=\"#FF1000\">%s</font></A>",
+				MY_CGI_URL, root, MESSAGEMAIN_moderate_delete_thread);
+		}
+
+		printf("</SMALL> ]</TD></TR></TABLE></CENTER>");
+	}
+	return 0;
+}
+
+/* print FAQ-Help page */
+void PrintFAQForm()
+{
+	size_t readed;
+	char *buf;
+	FILE *f;
+
+	/* print faq file */
+	if((buf = (char*)malloc(MAX_HTML_FILE_SIZE)) == NULL) printhtmlerror();
+	
+	if((f = fopen(F_FAQ_HELP, FILE_ACCESS_MODES_R)) == NULL) printhtmlerror();
+ 	//printhtmlerror();	
+	if((readed = fread(buf, 1, MAX_HTML_FILE_SIZE, f)) == 0) printhtmlerror();
+	if(fwrite(buf, 1, readed, stdout) != readed) printhtmlerror();
+	fclose(f);
+
+	free(buf);
+}
+
+void PrintSearchForm(char *s, DB_Base *db, int start = 0)
+{
+	printf("<FORM METHOD=POST ACTION=\"%s?search=action\">",
+		MY_CGI_URL);
+	
+	printf("<CENTER><P><B>%s</B><BR><P>", MESSAGEHEAD_search);
+
+	if(start) {
+		FILE *f;
+		char LastMsgStr[500];
+		DWORD LastMsg = 0, LastDate = 0;
+		f = fopen(F_SEARCH_LASTINDEX, FILE_ACCESS_MODES_R);
+		if(f != NULL) {
+			fscanf(f, "%d %d", &LastMsg, &LastDate);
+			fclose(f);
+		}
+		if(LastMsg != 0) {
+			SMessage mes;
+			if(ReadDBMessage(db->TranslateMsgIndex(LastMsg), &mes)) {
+				char s[200];
+				ConvertTime(mes.Date, s);
+				sprintf(LastMsgStr, "%d (%s)", LastMsg, s);
+			}
+			else strcpy(LastMsgStr, MESSAGEMAIN_search_indexerror);
+		}
+		else {
+			strcpy(LastMsgStr, MESSAGEMAIN_search_notindexed);
+		}
+		printf("<P>%s<P>%s : %s<P>", MESSAGEMAIN_search_howtouse, MESSAGEMAIN_search_lastindexed, LastMsgStr);
+	}
+
+	printf("<P><EM>%s</EM><BR>", MESSAGEMAIN_search_searchmsg);
+	printf("<INPUT TYPE=RADIO NAME=sel VALUE=1 CHECKED>%s <FONT FACE=\"Courier\">"
+		"<INPUT TYPE=TEXT NAME=\"find\" SIZE=45 VALUE=\"%s\"></FONT>", 
+			MESSAGEMAIN_search_containing, s);
+
+	
+	printf("<P><INPUT TYPE=SUBMIT VALUE=\"%s\"></CENTER></FORM>",
+		MESSAGEHEAD_search);
+}
+
+#if STABLE_TITLE == 0
+void Tittle_cat(char *s)
+{
+	// set title
+	ConfTitle = (char*)realloc(ConfTitle, strlen(ConfTitle) + strlen(TITLE_divider) + strlen(s) + 1);
+	strcat(ConfTitle, TITLE_divider);
+	strcat(ConfTitle, s);
+}
+#else
+#define Tittle_cat(x) {}
+#endif
+
+/* print create or edit(delete) profile form (depend of flags)
+ * if flags == 1 - Edit profile, otherwise create profile
+ */
+void PrintEditProfileForm(SProfile_UserInfo *ui, SProfile_FullUserInfo *fui, DWORD flags)
+{
+	char str1[20], str2[20], str3[20], str4[20], str5[20];
+	printf("<FORM METHOD=POST ACTION=\"%s?register=action\">",
+		MY_CGI_URL);
+
+	if(ULogin.LU.ID[0] == 0) {
+		printf(DESIGN_BEGIN_REGISTER_OPEN "<TD COLSPAN=2 ALIGN=CENTER>"
+			"<BIG>%s</BIG></TD></TR>", MESSAGEMAIN_register_intro);
+	}
+	else
+		printf(DESIGN_BEGIN_REGISTER_OPEN "<TD COLSPAN=2 ALIGN=CENTER>"
+			"<BIG>%s</BIG></TD></TR>", MESSAGEMAIN_register_chg_prof_intro);
+
+	printf("<TR><TD COLSPAN=2><HR ALIGN=CENTER WIDTH=80%% NOSHADE></TD></TR><TR><TD ALIGN=RIGHT>%s </TD>",
+			MESSAGEMAIN_register_login);
+
+	if( (ULogin.LU.ID[0] == 0) || (ULogin.LU.ID[0] != 0 && ((ULogin.pui->right & USERRIGHT_SUPERUSER) != 0)) ) {
+		printf("<TD><INPUT TYPE=TEXT NAME=\"login\" SIZE=35 MAXLENGTH=%d VALUE=\"%s\"></TD></TR>",
+			AUTHOR_NAME_LENGTH - 1, ui->username);
+	}
+	else {
+		printf("<TD>%s</TD></TR>", ui->username);
+	}
+
+	if( ULogin.LU.ID[0] != 0 && ((ULogin.LU.right & USERRIGHT_ALT_DISPLAY_NAME) != 0) ) {
+		printf("<TR><TD ALIGN=RIGHT>%s </TD><TD><INPUT TYPE=TEXT NAME=\"dispnm\" SIZE=35 MAXLENGTH=%d VALUE=\"%s\"></TD></TR>",
+			MESSAGEMAIN_register_displayname, PROFILES_MAX_ALT_DISPLAY_NAME - 1, ui->altdisplayname);
+	}
+
+	if((flags & 0x01) == 0) {
+		printf("<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>" MESSAGEMAIN_register_oldpass_req "</STRONG></TR>" \
+			   "<TR><TD ALIGN=RIGHT>%s </TD><TD><INPUT TYPE=PASSWORD NAME=\"opswd\" SIZE=35 " \
+			   "MAXLENGTH=%d VALUE=\"\"></TD></TR>",
+				MESSAGEMAIN_register_oldpassword, PROFILES_MAX_PASSWORD_LENGTH - 1);
+	}
+
+	if(ui->Flags & PROFILES_FLAG_VISIBLE_EMAIL)
+		strcpy(str1, RADIO_CHECKED);
+	else *str1 = 0;
+
+	printf("<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>" MESSAGEMAIN_register_if_want_change "</STRONG></TR>" \
+"<TR><TD ALIGN=RIGHT>%s </TD><TD><INPUT TYPE=PASSWORD NAME=\"pswd1\" SIZE=35 MAXLENGTH=%d VALUE=\"%s\"></TD></TR>" \
+"<TR><TD ALIGN=RIGHT>%s </TD><TD><INPUT TYPE=PASSWORD NAME=\"pswd2\" SIZE=35 MAXLENGTH=%d VALUE=\"%s\"></TD></TR>" \
+"<TR><TD ALIGN=RIGHT>%s </TD><TD><INPUT TYPE=TEXT NAME=\"name\" SIZE=35 MAXLENGTH=%d VALUE=\"%s\"></TD></TR>" \
+"<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>" MESSAGEMAIN_register_validemail_req "</STRONG></TR>" \
+"<TR><TD ALIGN=RIGHT>%s </TD><TD><INPUT TYPE=TEXT NAME=\"email\" SIZE=35 MAXLENGTH=%d VALUE=\"%s\"></TD></TR>" \
+"<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG><INPUT TYPE=CHECKBOX NAME=\"pem\" VALUE=1%s></TD></TR>" \
+"<TR><TD ALIGN=RIGHT>%s </TD><TD><INPUT TYPE=TEXT NAME=\"hpage\" SIZE=35 MAXLENGTH=%d VALUE=\"%s\"></TD></TR>" \
+"<TR><TD ALIGN=RIGHT>%s </TD><TD><INPUT TYPE=TEXT NAME=\"icq\" SIZE=15 MAXLENGTH=%d VALUE=\"%s\"></TD></TR>",
+		  MESSAGEMAIN_register_password1, PROFILES_MAX_PASSWORD_LENGTH - 1, "",
+		  MESSAGEMAIN_register_password2, PROFILES_MAX_PASSWORD_LENGTH - 1, "",
+		  MESSAGEMAIN_register_full_name, PROFILES_FULL_USERINFO_MAX_NAME - 1, fui->FullName,
+		  MESSAGEMAIN_register_email, PROFILES_FULL_USERINFO_MAX_EMAIL - 1, fui->Email,
+		  MESSAGEMAIN_register_email_pub, str1, MESSAGEMAIN_register_homepage,
+		  PROFILES_FULL_USERINFO_MAX_HOMEPAGE - 1, fui->HomePage,
+		  MESSAGEMAIN_register_icq, PROFILES_MAX_ICQ_LEN - 1, ui->icqnumber
+		  );
+
+	if((ui->Flags & PROFILES_FLAG_INVISIBLE) == 0)
+		strcpy(str1, RADIO_CHECKED);
+	else *str1 = 0;
+
+	if((ui->Flags & PROFILES_FLAG_PERSMSGDISABLED) != 0)
+		strcpy(str2, RADIO_CHECKED);
+	else *str2 = 0;
+
+	if((ui->Flags & PROFILES_FLAG_PERSMSGTOEMAIL) != 0)
+		strcpy(str3, RADIO_CHECKED);
+	else *str3 = 0;
+
+	if((ui->Flags & PROFILES_FLAG_ALWAYS_EMAIL_ACKN) != 0)
+		strcpy(str4, RADIO_CHECKED);
+	else *str4 = 0;
+
+    if((ui->Flags & PROFILES_FLAG_VIEW_SETTINGS) != 0)
+        strcpy(str5, RADIO_CHECKED);
+    else *str5 = 0;
+			
+	fui->SelectedUsers[PROFILES_FULL_USERINFO_MAX_SELECTEDUSR - 1] = 0;	// FIX
+   
+	printf(
+"<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG><BR><TEXTAREA COLS=60 ROWS=3 NAME=\"about\" WRAP=VIRTUAL>%s</TEXTAREA></TD></TR>" \
+"<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG><BR><TEXTAREA COLS=60 ROWS=3 NAME=\"sign\" WRAP=VIRTUAL>%s</TEXTAREA></TD></TR>" \
+"<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG><BR><TEXTAREA COLS=30 ROWS=4 NAME=\"susr\" WRAP=VIRTUAL>%s</TEXTAREA></TD></TR>" \
+"<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG><INPUT TYPE=CHECKBOX NAME=\"vprf\" VALUE=1%s></TD></TR>" \
+"<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG><INPUT TYPE=CHECKBOX NAME=\"apem\" VALUE=1%s></TD></TR>"	\
+"<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG><INPUT TYPE=CHECKBOX NAME=\"pdis\" VALUE=1%s></TD></TR>" \
+"<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG><INPUT TYPE=CHECKBOX NAME=\"peml\" VALUE=1%s></TD></TR>" \
+"<TR><TD COLSPAN=2 ALIGN=CENTER><STRONG>%s</STRONG><INPUT TYPE=CHECKBOX NAME=\"vprs\" VALUE=1%s></TD></TR>",
+			MESSAGEMAIN_register_about, fui->AboutUser,
+			MESSAGEMAIN_register_signature, fui->Signature,
+			MESSAGEMAIN_register_selectedusers, fui->SelectedUsers,
+			MESSAGEMAIN_register_private_prof, str1,
+			MESSAGEMAIN_register_always_emlackn, str4,
+			MESSAGEMAIN_register_pmsg_disable, str2,
+			MESSAGEMAIN_register_pmsg_email, str3,
+			MESSAGEMAIN_register_view_saving, str5
+		);
+
+	printf("<TR><TD COLSPAN=2></TR><TR><TD COLSPAN=2 ALIGN=CENTER><B><FONT COLOR=RED>" \
+		   MESSAGEMAIN_register_req_fields "</FONT><B></TR><TR><TD COLSPAN=2>" \
+		   "<HR ALIGN=CENTER WIDTH=80%% NOSHADE></TR><TR><TD COLSPAN=2 ALIGN=CENTER>");
+
+	/* print buttons */
+	if(flags & 0x01)
+		printf("<INPUT TYPE=SUBMIT NAME=\"register\" VALUE=\"%s\">&nbsp;", MESSAGEMAIN_register_register);
+
+	if(flags & 0x02)
+		printf("<INPUT TYPE=SUBMIT NAME=\"register\" VALUE=\"%s\">&nbsp;",  MESSAGEMAIN_register_edit);
+
+	if(flags & 0x04)
+		printf(
+		"<INPUT TYPE=SUBMIT NAME=\"register\" VALUE=\"" MESSAGEMAIN_register_delete "\">" 
+		"<INPUT TYPE=CHECKBOX NAME=\"" CONFIRM_DELETE_CHECKBOX_TEXT "\" VALUE=\"true\">" 
+		MESSAGEMAIN_register_confirm_delete);
+
+	printf("</TD></TR>" DESIGN_END_REGISTER_CLOSE "</FORM>");
+}
+
+
+void PrintSessionsList(DWORD Uid)
+{
+	char **buf = NULL;
+	char name[1000];
+	DWORD sc = 0, i;
+	DWORD seqid[2], userid;
+	if(ULogin.GenerateListSessionForUser(&buf, &sc, Uid)){
+
+		if(sc){
+			printf(DESIGN_BEGIN_USERINFO_INTRO_OPEN);
+			for(i = 0; i < sc; i++) {
+				unsigned char *seqip = (unsigned char*)(buf[i]+4);
+				seqid[0] = *((DWORD*)(buf[i]+8));
+				seqid[1] = *((DWORD*)(buf[i]+12));
+				userid = *((DWORD*)(buf[i]+16));
+				time_t seqtime = *((DWORD*)(buf[i]));
+				char *seqdate;
+				if( seqtime > time(NULL)) seqdate = (char*)ConvertFullTime(seqtime-USER_SESSION_LIVE_TIME);
+				else seqdate = (char*)ConvertFullTime(seqtime);
+
+				printf("<TR><TD ALIGN=RIGHT>%ld. "MESSAGEMAIN_session_ip"</TD><TD"
+					" ALIGN=LEFT><STRONG>%u.%u.%u.%u</STRONG> %s</TD></TR>",
+					i+1, seqip[0] & 0xff, seqip[1] & 0xff, seqip[2] & 0xff, seqip[3] & 0xff, 
+					userid & SEQUENCE_IP_CHECK_DISABLED ? MESSAGEMAIN_session_ip_nocheck : MESSAGEMAIN_session_ip_check );
+					 
+				printf("<TR><TD ALIGN=RIGHT>"MESSAGEMAIN_session_date"</TD><TD ALIGN=LEFT>"
+					" <STRONG>%s</STRONG></TD></TR>", seqdate);
+				printf("<TR><TD ALIGN=RIGHT>"MESSAGEMAIN_session_state"</TD><TD ALIGN=LEFT><STRONG>");
+
+				if( seqtime > time(NULL) ) {
+					printf(MESSAGEMAIN_session_state_active);
+
+					if( (ULogin.LU.right & USERRIGHT_SUPERUSER) != 0  || ( ULogin.LU.UniqID == Uid && ( ULogin.LU.right & USERRIGTH_PROFILE_MODIFY) != 0 ) )
+						printf(" [<a href=\"%s?clsession1=%ld&clsession2=%ld\">"MESSAGEMAIN_session_state_toclose"</a>]", MY_CGI_URL, seqid[0], seqid[1]);
+				}
+				else  printf(MESSAGEMAIN_session_state_closed);
+				printf("</STRONG></TD></TR><TR><TD><BR></TD></TR>");
+				free(buf[i]);
+			}
+			printf(DESIGN_END_USERINFO_INTRO_CLOSE);
+		}
+		else printf(DESIGN_BEGIN_USERINFO_INTRO_OPEN "<TR><TD ALIGN=CENTER><B>"
+			MESSAGEMAIN_session_no "</B></TD></TR>" DESIGN_END_USERINFO_INTRO_CLOSE);
+	}
+	else printhtmlerror();
+	if(buf) free(buf);
+}
+																																																																																																																																									
+int PrintAboutUserInfo(char *name)
+{
+	char *nickname;
+	CProfiles *mprf = new CProfiles();
+	if(mprf->errnum != PROFILE_RETURN_ALLOK) {
+#if ENABLE_LOG >= 1
+		print2log("error working with profiles database (init)");
+#endif
+		return 0;
+	}
+	SProfile_FullUserInfo fui;
+	SProfile_UserInfo ui;
+
+	nickname = FilterHTMLTags(name, 1000);
+
+	if(mprf->GetUserByName(name, &ui, &fui, NULL) != PROFILE_RETURN_ALLOK)
+	{
+		delete mprf;
+		printf(MESSAGEMAIN_profview_no_user, nickname);
+
+		return 1;
+	}
+
+/**********/
+	if(strcmp(name, "www") == 0) print2log("Profile www was accessed by %s", getenv("REMOTE_ADDR"));
+/**********/
+
+	printf("<P></P>" DESIGN_BEGIN_USERINFO_INTRO_OPEN
+		"<TD COLSPAN=2><BIG>%s %s</BIG></TD></TR>", MESSAGEMAIN_profview_intro, nickname);
+	
+	printf("<TR><TD COLSPAN=2><HR ALIGN=CENTER WIDTH=80%% NOSHADE></TR>");
+
+	printf("<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>%s</STRONG><SMALL>", MESSAGEMAIN_profview_login, nickname );
+	
+
+	if(ULogin.LU.UniqID == ui.UniqID){
+		printf(" <A HREF=\"?register=form\">(%s)</A>", MESSAGEMAIN_profview_editinfo);
+	}
+	
+	if(ULogin.LU.ID[0] && ULogin.LU.UniqID != ui.UniqID){
+		printf(" <A HREF=\"?persmsgform=%s\">(%s)</A>", CodeHttpString(name), MESSAGEMAIN_profview_postpersmsg);
+	}
+
+	printf("</SMALL></TD></TR>");
+
+	if((ui.Flags & PROFILES_FLAG_ALT_DISPLAY_NAME) != 0) {
+		char *st;
+		if(!PrepareTextForPrint(ui.altdisplayname, &st, ui.secheader/*security*/,
+			MESSAGE_ENABLED_TAGS | BOARDTAGS_PURL_ENABLE))
+		{
+			st = (char*)malloc(1000);
+			strcpy(st, ui.altdisplayname);
+		}
+		printf("<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>%s</STRONG></TD></TR>",
+				MESSAGEMAIN_profview_altname, st);
+		free(st);
+	}
+
+	if(((ui.Flags & PROFILES_FLAG_INVISIBLE) == 0) || (ULogin.LU.right & USERRIGHT_SUPERUSER) ||
+		(ULogin.LU.UniqID == ui.UniqID) )
+	{
+		printf("<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>%s</STRONG></TD></TR>" \
+			"<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG><A HREF=\"%s\">%s</A></STRONG></TD></TR>",
+			MESSAGEMAIN_profview_fullname,	fui.FullName,
+			MESSAGEMAIN_profview_homepage,	fui.HomePage, fui.HomePage);
+		
+		/* if invisible mail - allow view only for same user or superuser */
+		if((ui.Flags & PROFILES_FLAG_VISIBLE_EMAIL) || (ULogin.LU.right & USERRIGHT_SUPERUSER) ||
+			(ULogin.LU.UniqID == ui.UniqID)) {
+			printf("<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG><A HREF=mailto:%s>%s</A></STRONG></TD></TR>",
+				MESSAGEMAIN_profview_email, fui.Email, fui.Email);
+		}
+		else printf("<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG><FONT COLOR=#0000F0>%s</FONT></STRONG></TD></TR>",
+			MESSAGEMAIN_profview_email, MESSAGEMAIN_profview_privacy_inf);
+		
+		/* possible error (with malloc) here */
+		char *regdate, *logdate = (char*)malloc(255), *ustatus = (char*)malloc(255);
+		/*************************************/
+		if(!ui.LoginDate) strcpy(logdate, "Never logged in");
+		else strcpy(logdate, (char*)ConvertFullTime(ui.LoginDate));
+		regdate = (char*)ConvertFullTime(fui.CreateDate);
+
+		// set up ustatus
+		if((ui.right & USERRIGHT_SUPERUSER) && ((ULogin.LU.right & USERRIGHT_SUPERUSER) || (strcmp(name, "www") /*&& strcmp(name, "Jul'etka") */))) {
+			strcpy(ustatus, MESSAGEMAIN_profview_u_moderator);
+		}
+		else {
+			strcpy(ustatus, MESSAGEMAIN_profview_u_user);
+		}
+
+		//	check for too high value in status
+		if(ui.Status >= USER_STATUS_COUNT) ui.Status = USER_STATUS_COUNT - 1;	// maximum status
+
+		//strcat(ustatus, " ( ");
+		//strcat(ustatus, UserStatus_List[ui.Status]);
+		//strcat(ustatus, " )");
+
+		ui.icqnumber[15] = 0;	//	FIX
+
+		char icqpic[1000];
+		icqpic[0] = 0;
+
+		if(strlen(ui.icqnumber) > 0) {
+			sprintf(icqpic, "<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>" \
+				"<IMG src=\"http://online.mirabilis.com/scripts/online.dll?icq=%s&img=5\">%s</STRONG></TD></TR><BR>",
+				MESSAGEMAIN_profview_user_icq, ui.icqnumber, ui.icqnumber);
+		}
+
+		printf("%s<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>%s</STRONG></TD></TR>" \
+"<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>%ld</STRONG></TD></TR>" \
+"<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>%s</STRONG></TD></TR>" \
+"<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>%s</STRONG></TD></TR>" \
+"<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>%s</STRONG></TD></TR>",
+			   icqpic,
+			   MESSAGEMAIN_profview_user_status,	ustatus,
+			   MESSAGEMAIN_profview_postcount,		ui.postcount,
+			   MESSAGEMAIN_profview_reg_date,		regdate,
+			   MESSAGEMAIN_profview_login_date,		logdate,
+			   MESSAGEMAIN_profview_about_user,		fui.AboutUser);
+
+		if((ULogin.LU.right & USERRIGHT_SUPERUSER) || (ULogin.LU.UniqID == ui.UniqID) ) {
+			char hname[10000];
+			hostent *he;
+			unsigned char *aa = (unsigned char *)(&ui.lastIP);
+			sprintf(hname, "%u.%u.%u.%u", aa[0] & 0xff, aa[1] & 0xff, aa[2] & 0xff, aa[3] & 0xff);
+			if((he = gethostbyaddr((char*)(&ui.lastIP), 4, AF_INET)) != NULL) {
+				// prevent saving bad hostname
+				if(strlen(he->h_name) > 0) {
+					char tmp[1000];
+
+					strcpy(tmp, hname);
+					strncpy(hname, he->h_name, 9999);
+					strcat(hname, " (");
+					strcat(hname, tmp);
+					strcat(hname, ")");
+				}
+			}
+			// only for admin :)
+			if((ULogin.LU.right & USERRIGHT_SUPERUSER) != 0)
+				printf("<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>%d</STRONG></TD></TR>", 
+					MESSAGEMAIN_profview_refreshcnt, ui.RefreshCount);
+			printf("<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>%s</STRONG></TD></TR>",
+				MESSAGEMAIN_profview_lastip, hname);
+			printf("<TR><TD ALIGN=RIGHT>%s</TD><TD><STRONG>%d(%d)</STRONG></TD></TR>",
+			        MESSAGEMAIN_profview_persmsgcnt, ui.persmescnt, ui.readpersmescnt);
+		}
+
+		free(logdate);
+		free(ustatus);
+	}
+	else {
+		printf("<TR><TD COLSPAN=2><BIG>%s</BIG></TD></TR><BR>", MESSAGEMAIN_profview_privacy_prof);
+	}
+	printf(DESIGN_END_USERINFO_INTRO_CLOSE);
+
+
+	printf("<BR>");
+
+  if((ULogin.LU.right & USERRIGHT_SUPERUSER) || (ULogin.LU.UniqID == ui.UniqID) ) {
+	PrintSessionsList(ui.UniqID);
+
+  }
+
+	//
+	//	if admin print profile modification form
+	//
+	if((ULogin.LU.right & USERRIGHT_SUPERUSER)) {
+		char sel[100];
+		BYTE i;
+		printf("<BR><CENTER><FORM METHOD=POST ACTION=\"%s?changeusr=action\"> User Status: ", MY_CGI_URL);
+
+		printf("<SELECT NAME=\"ustat\">");
+		for(i = 0; i < USER_STATUS_COUNT; i++) {
+
+			if(i == ui.Status) strcpy(sel, LISTBOX_SELECTED);
+			else strcpy(sel, "");
+
+			printf("<OPTION VALUE=\"%d\"%s>%s", i, sel, UserStatus_List[i]);
+		}
+		printf("</SELECT>");
+
+		printf("<BR>" MESSAGEMAIN_profview_sechdr "<INPUT TYPE=TEXT SIZE=3 NAME=\"sechdr\" VALUE=\"%d\">", (DWORD)ui.secheader);
+		printf("<BR>" MESSAGEMAIN_profview_secbdy "<INPUT TYPE=TEXT SIZE=3 NAME=\"secbdy\" VALUE=\"%d\">", (DWORD)ui.secur);
+		printf("<INPUT TYPE=HIDDEN SIZE=0 NAME=\"name\" VALUE=\"%s\">", nickname);
+
+		// user rights here
+		puts("<BR><P><TABLE BORDER=1 CELLSPACING=0 CELLPADDING=6 BGCOLOR=#FFFFFF><TR><TH ALIGN=RIGHT>");
+		for(i = 0; i < USERRIGHT_COUNT; i++)
+		{
+			if( (ui.right & (1<<i)) != 0)
+				strcpy(sel, RADIO_CHECKED);
+			else sel[0] = 0;
+			printf("%s <INPUT TYPE=CHECKBOX NAME=\"right%d\"%s><BR>",
+				UserRight_List[i], i, sel);
+		}
+		puts("</TH></TR></TABLE>");
+
+		printf("<BR><BR><INPUT TYPE=SUBMIT NAME=\"update\" VALUE=\"%s\">", MESSAGEMAIN_register_edit);
+
+		printf("</FORM></CENTER>");
+	}
+
+	free(nickname);
+	delete mprf;
+
+	return 1;
+}
+
+// string compare
+static int cmp_name(const void *p1, const void *p2)
+{
+	char upper[2][AUTHOR_NAME_LENGTH];
+	strcpy(upper[0], (*(char **)p1) + 20);
+	strcpy(upper[1], (*(char **)p2) + 20);
+	for(int i = 0; i < 2; i++) 
+		toupperstr(upper[i]);
+	
+	return strcmp(upper[0], upper[1]);
+}
+
+// by last ip
+static int cmp_ip(const void *p1, const void *p2)
+{
+	return int( ntohl((*((DWORD**)p1))[0]) - ntohl((*((DWORD**)p2))[0]) );
+}
+
+// by postcount
+static int cmp_postcount(const void *p1, const void *p2)
+{
+	return int( (*((DWORD**)p2))[1] - (*((DWORD**)p1))[1] );
+}
+
+// by refresh count
+static int cmp_refreshcount(const void *p1, const void *p2)
+{
+	return int( (*((DWORD**)p2))[3] - (*((DWORD**)p1))[3] );
+}
+
+// by last login date
+static int cmp_date(const void *p1, const void *p2)
+{
+	return int( (*((DWORD**)p2))[2] - (*((DWORD**)p1))[2] );
+}
+
+// by security right
+static int cmp_right(const void *p1, const void *p2)
+{
+	return int( (*((DWORD**)p1))[4] - (*((DWORD**)p2))[4] );
+}
+
+void PrintUserList(DB_Base *dbb, int code)
+{
+	char **buf = NULL;
+	char name[1000];
+	DWORD uc = 0, i;
+	CProfiles uprof;
+
+	if(!uprof.GenerateUserList(&buf, &uc))
+		printhtmlerror();
+
+	// Print header of user list
+	printf("<CENTER><P><B>%s</B><BR>%s%d<P>", MESSAGEHEAD_userlist, MESSAGEMAIN_total_user_count, uc);
+
+	switch(code) {
+		case 1:
+			qsort((void *)buf, uc, sizeof(char*), cmp_name);
+			break;
+		case 2:
+			qsort((void *)buf, uc, sizeof(char*), cmp_postcount);
+			break;
+		case 3:
+			qsort((void *)buf, uc, sizeof(char*), cmp_ip);
+			break;
+		case 4:
+			qsort((void *)buf, uc, sizeof(char*), cmp_date);
+			break;
+		case 5:
+			qsort((void *)buf, uc, sizeof(char*), cmp_refreshcount);
+			break;
+		case 6:
+			qsort((void *)buf, uc, sizeof(char*), cmp_right);
+			break;
+	}
+
+	// print sort link bar
+	if((ULogin.LU.right & USERRIGHT_SUPERUSER)) {
+		printf("<B>%s</B>", MESSAGEMAIN_userlist_sortby);
+		if(code != 1) printf("<A HREF=\"%s?userlist=1\">%s</A> | ", MY_CGI_URL, MESSAGEMAIN_userlist_sortbyname);
+		else printf("<B>%s</B> | ", MESSAGEMAIN_userlist_sortbyname);
+		if(code != 2) printf("<A HREF=\"%s?userlist=2\">%s</A> | ", MY_CGI_URL, MESSAGEMAIN_userlist_sortbypcnt);
+		else printf("<B>%s</B> | ", MESSAGEMAIN_userlist_sortbypcnt);
+		if(code != 3) printf("<A HREF=\"%s?userlist=3\">%s</A> | ", MY_CGI_URL, MESSAGEMAIN_userlist_sortbyhost);
+		else printf("<B>%s</B> | ", MESSAGEMAIN_userlist_sortbyhost);
+		if(code != 4) printf("<A HREF=\"%s?userlist=4\">%s</A> | ", MY_CGI_URL, MESSAGEMAIN_userlist_sortbydate);
+		else printf("<B>%s</B> | ", MESSAGEMAIN_userlist_sortbydate);
+		if(code != 5) printf("<A HREF=\"%s?userlist=5\">%s</A> | ", MY_CGI_URL, MESSAGEMAIN_userlist_sortbyrefresh);
+		else printf("<B>%s</B> | ", MESSAGEMAIN_userlist_sortbyrefresh);
+		if(code != 6) printf("<A HREF=\"%s?userlist=6\">%s</A><BR><BR>", MY_CGI_URL, MESSAGEMAIN_userlist_sortbyright);
+		else printf("<B>%s</B><BR><BR>", MESSAGEMAIN_userlist_sortbyright);
+	}
+
+	DWORD oldval;
+	if(uc) {
+		unsigned char *aa = (unsigned char*)buf[0];
+		switch(code) {
+			case 2:
+				oldval = *((DWORD*)(buf[0] + 4));
+				printf("<B>(%lu)</B><BR>", *((DWORD*)(buf[0] + 4)));
+				break;
+			case 3:
+				oldval = *((DWORD*)(buf[0]));
+				printf("<B>(%u.%u.%u.%u)</B><BR>", aa[0] & 0xff, aa[1] & 0xff, aa[2] & 0xff, aa[3] & 0xff);
+				break;
+			case 4:
+				// not used yet
+				break;
+			case 5:
+				oldval = *((DWORD*)(buf[0] + 12));
+				printf("<B>(%lu)</B><BR>", *((DWORD*)(buf[0] + 12)));
+				break;
+			case 6:
+				oldval = *((DWORD*)(buf[0] + 16));
+				printf("<B>(%08x)</B><BR>", *((DWORD*)(buf[0] + 16)));
+				break;
+		}
+	}
+	int cc = 0;
+	// print begin
+	for(i = 0; i < uc; i++) {
+		switch(code) {
+			case 2:
+				if(oldval != *((DWORD*)(buf[i] + 4))) {
+					printf("<BR><BR><B>(%lu)</B><BR>", *((DWORD*)(buf[i] + 4)));
+					oldval = *((DWORD*)(buf[i] + 4));
+					cc = 0;
+				}
+				break;
+			case 3:
+				if(oldval != *((DWORD*)(buf[i]))) {
+					unsigned char *aa = (unsigned char*)buf[i];
+					printf("<BR><BR><B>(%u.%u.%u.%u)</B><BR>", aa[0] & 0xff, aa[1] & 0xff, aa[2] & 0xff, aa[3] & 0xff);
+					oldval = *((DWORD*)(buf[i]));
+					cc = 0;
+				}
+				break;
+			case 4:
+				break;
+			case 5:
+				if(oldval != *((DWORD*)(buf[i] + 12))) {
+					printf("<BR><BR><B>(%lu)</B><BR>", *((DWORD*)(buf[i] + 12)));
+					oldval = *((DWORD*)(buf[i] + 12));
+					cc = 0;
+				}
+				break;
+			case 6:
+				if(oldval != *((DWORD*)(buf[i] + 16))) {
+					printf("<BR><BR><B>(%08x)</B><BR>", *((DWORD*)(buf[i] + 16)));
+					oldval = *((DWORD*)(buf[i] + 16));
+					cc = 0;
+				}
+				break;
+		}
+		if((cc % 10) != 0) printf(" | ");
+		if(((cc % 10) == 0) && cc != 0) {
+			// print end and begin
+			printf("</CENTER><BR><CENTER>");
+		}
+		cc++;
+
+		dbb->Profile_UserName(buf[i] + 20, name, 1);
+		printf("%s", name);
+		free(buf[i]);
+	}
+	if(buf) free(buf);
+	printf("</CENTER>");
+}
+
+/* create or update user profile
+ * if op == 1 - create
+ * if op == 2 - update
+ * if op == 3 - delete
+ */
+int CheckAndCreateProfile(SProfile_UserInfo *ui, SProfile_FullUserInfo *fui, char *p2, char *oldp, int op, char *deal)
+{
+	CProfiles *uprof;
+	DWORD err = 0, needregisteraltnick = 0;
+
+	/* password check */
+	if((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0) {
+		/* old password */
+		if(op != 1 && (ULogin.LU.ID[0] == 0 || (strcmp(oldp, ULogin.pui->password) != 0) ||
+			(strcmp(ULogin.pui->username, ui->username) != 0)))
+			return PROFILE_CHK_ERROR_INVALID_PASSWORD;
+	}
+	/* password and confirm password */
+	if(op != 3 && (strcmp(ui->password, p2) != 0 || (strlen(p2) < PROFILES_MIN_PASSWORD_LENGTH) && strlen(p2) != 0))
+		return PROFILE_CHK_ERROR_INVALID_PASSWORD_REP;
+	
+	if(strlen(p2) == 0) {
+		if(ULogin.LU.ID[0] != 0) strcpy(ui->password, ULogin.pui->password);
+		else return PROFILE_CHK_ERROR_INVALID_PASSWORD_REP;
+	}
+
+	// ************ delete ************
+	if(op == 3) {
+		if((ULogin.LU.ID[0] == 0 || strcmp(ULogin.pui->username, ui->username) != 0 ||
+			(ULogin.LU.right & USERRIGTH_PROFILE_MODIFY) == 0) && (!(ULogin.LU.right & USERRIGHT_SUPERUSER)))
+			return PROFILE_CHK_ERROR_CANNOT_DELETE_USR;
+
+		uprof = new CProfiles();
+
+		SProfile_UserInfo nui;
+		err = uprof->GetUserByName(ui->username, &nui, fui, NULL);
+		if(err == PROFILE_RETURN_ALLOK) {
+			// check for special admitions
+			if(nui.altdisplayname[0] != 0 && (nui.Flags & PROFILES_FLAG_ALT_DISPLAY_NAME) ) {
+				// need to delete alternative spelling too
+				ui->UniqID = nui.UniqID;
+				needregisteraltnick = 1;
+			}
+
+			// deleting user
+			err = uprof->DeleteUser(ui->username);
+			// check result of operation
+			if(err == PROFILE_RETURN_ALLOK) {
+				if(ULogin.LU.UniqID == nui.UniqID)
+					ULogin.CloseSession(ULogin.LU.ID); // user deleted itself
+				else ULogin.ForceCloseSessionForUser(nui.UniqID); // superuser delete smb.
+			}
+		}
+		goto cleanup_and_parseerror;
+	}
+
+	/* Now we know that it can't be user deletion, so check common parameters */
+
+	if(fui->Signature[0] != 0) {
+		ui->Flags = ui->Flags | PROFILES_FLAG_HAVE_SIGNATURE;
+	}
+
+	if(ui->altdisplayname[0] != 0 && /*security check*/ (ULogin.LU.ID[0] != 0 && (ULogin.LU.right & USERRIGHT_ALT_DISPLAY_NAME) != 0 ) ) {
+		ui->Flags |= PROFILES_FLAG_ALT_DISPLAY_NAME;
+		needregisteraltnick = 1;
+	}
+	else {
+		ui->Flags &= (~PROFILES_FLAG_ALT_DISPLAY_NAME);
+		if( (ULogin.LU.ID[0] != 0 && (ULogin.LU.right & USERRIGHT_ALT_DISPLAY_NAME) != 0 ) ) needregisteraltnick = 1;
+	}
+
+	/* common email check (if requred vaild email) */
+	if(IsMailCorrect(fui->Email) == 0)
+		return PROFILE_CHK_ERROR_INVALID_EMAIL;
+
+	uprof = new CProfiles();
+
+	// ********** update **********
+	if(op == 2) {
+		err = uprof->ModifyUser(ui, fui, NULL);
+		goto cleanup_and_parseerror;
+	}
+
+	// ********** create **********
+	if(op == 1) {
+		ui->lastIP = Nip;
+		err = uprof->AddNewUser(ui, fui, NULL);
+		goto cleanup_and_parseerror;
+	}
+
+	delete uprof;
+
+	printhtmlerror();
+
+cleanup_and_parseerror:
+
+	delete uprof;
+
+	switch(err) {
+	case PROFILE_RETURN_ALLOK:
+		{
+			// Do post user creation/modificaton job
+#if USER_ALT_NICK_SPELLING_SUPPORT
+			if(op == 1 || op == 2 && needregisteraltnick) {
+				if(ui->altdisplayname[0] != 0) {
+					char *st;
+
+					// parse tags
+					if(!PrepareTextForPrint(ui->altdisplayname, &st, ui->secheader/*security*/,
+							MESSAGE_ENABLED_TAGS | BOARDTAGS_PURL_ENABLE)) {
+						st = (char*)malloc(1000);
+						strcpy(st, ui->altdisplayname);
+					}
+
+					AltNames.AddAltName(ui->UniqID, ui->username, st);
+					free(st);
+				}
+				else AltNames.DeleteAltName(ui->UniqID);
+			}
+			else if(op == 3 && needregisteraltnick) {
+				AltNames.DeleteAltName(ui->UniqID);
+			}
+#endif
+		}
+		return PROFILE_CHK_ERROR_ALLOK;
+
+	case PROFILE_RETURN_ALREADY_EXIST:
+		return PROFILE_CHK_ERROR_ALREADY_EXIST;
+
+	case PROFILE_RETURN_DB_ERROR:
+#if ENABLE_LOG >= 1
+		print2log("Profiles database error: DB ERROR, deal=%s", deal);
+#endif 
+		printhtmlerror();
+
+	case PROFILE_RETURN_INVALID_FORMAT:
+#if ENABLE_LOG >= 1
+		print2log("Profiles database error: INVALID FORMAT, deal=%s", deal);
+#endif
+		printhtmlerror();
+
+	case PROFILE_RETURN_INVALID_LOGIN:
+		if(op == 1 || op == 2)
+			return PROFILE_CHK_ERROR_INVALID_LOGIN_SPELL;
+		return PROFILE_CHK_ERROR_CANNOT_DELETE_USR;
+
+	case PROFILE_RETURN_INVALID_PASSWORD:
+		return PROFILE_CHK_ERROR_INVALID_PASSWORD;
+
+	case PROFILE_RETURN_PASSWORD_SHORT:
+		return PROFILE_CHK_ERROR_SHORT_PASSWORD;
+
+	case PROFILE_RETURN_UNKNOWN_ERROR:
+	default:
+#if ENABLE_LOG >= 1
+		print2log("profiles database error : UNKNOWN, deal=%s", deal);
+#endif 
+		printhtmlerror();
+	}
+}
+
+void PrintFavouritesList()
+{	
+
+	printf("<CENTER><P><B>%s</B><BR>", MESSAGEHEAD_favourites);
+	//for( int i=0; i<20; i++){
+	//			printf("ULogin.pui->favs[%ld]=%ld<br>",i, ULogin.pui->favs[i]);
+	//}
+	//DB.PrintHtmlMessageBufferByVI(ULogin.pui->favs, PROFILES_FAV_THREADS_COUNT);
+	printf("</CENTER>");
+}
+
+
+/* complete operation with user profile and print 
+ * result of execution
+ * op == 1 create
+ * op == 2 update
+ * op == 3 delete
+ */
+void DoCheckAndCreateProfile(SProfile_UserInfo *ui, SProfile_FullUserInfo *fui, char *passwdconfirm, char *oldpasswd, int op, char *deal)
+{
+	int err;
+	DWORD delme = 0;
+	
+	if(ULogin.LU.ID[0] != 0 && strcmp(ui->username, ULogin.pui->username) == 0 && op == 3) {
+		delme = 1;
+	}
+	
+	if(op == 1 ) {
+		char *f = FilterWhitespaces(ui->username);
+		memmove(ui->username, f, strlen(f) + 1);
+	}
+
+	print2log("DoCheckAndCreateProfile: user '%s', op=%d, (by %s)", ui->username, op, ULogin.LU.ID[0] != 0 ? ULogin.pui->username : "anonymous");
+	err = CheckAndCreateProfile(ui, fui, passwdconfirm, oldpasswd, op, deal);
+
+	if(err != PROFILE_CHK_ERROR_ALLOK)
+		PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+	char *tmp;
+
+	switch(err) {
+	case PROFILE_CHK_ERROR_ALLOK:
+		if(op == 3) {
+			PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE,
+			MAINPAGE_INDEX);
+			if(!delme)
+				PrintBoardError(MESSAGEMAIN_register_delete_ex, MESSAGEMAIN_register_delete_ex2,
+					HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+			else
+				PrintBoardError(MESSAGEMAIN_register_delete_logoff, MESSAGEMAIN_register_delete_logoff2,
+					HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+		}
+		else {
+			if(op == 1) {
+				/* if session already opened - close it */
+				if(ULogin.LU.ID[0] != 0)
+					ULogin.CloseSession(ULogin.LU.ID);
+
+				if(ULogin.OpenSession(ui->username, ui->password, NULL, Nip, 0) == 1) {
+					// entered, set new cookie
+					cookie_name = (char*)realloc(cookie_name, AUTHOR_NAME_LENGTH);
+					strcpy(cookie_name, ui->username);
+				}
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE,
+					MAINPAGE_INDEX);
+				PrintBoardError(MESSAGEMAIN_register_create_ex, MESSAGEMAIN_register_create_ex2,
+					HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+			}
+			else {
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE,
+					MAINPAGE_INDEX);
+				PrintBoardError(MESSAGEMAIN_register_edit_ex, MESSAGEMAIN_register_edit_ex2,
+					HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+			}
+		}
+
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE,
+			MAINPAGE_INDEX);
+		break;
+	case PROFILE_CHK_ERROR_ALREADY_EXIST:
+		PrintBoardError(MESSAGEMAIN_register_already_exit, MESSAGEMAIN_register_already_exit2, 0);
+		break;
+	case PROFILE_CHK_ERROR_NOT_EXIST:
+		PrintBoardError(MESSAGEMAIN_register_invalid_psw, MESSAGEMAIN_register_invalid_psw2, 0);
+		break;
+	case PROFILE_CHK_ERROR_INVALID_LOGIN_SPELL:
+		PrintBoardError(MESSAGEMAIN_register_invalid_lg_spell, MESSAGEMAIN_register_invalid_lg_spell2, 0);
+		break;
+	case PROFILE_CHK_ERROR_INVALID_PASSWORD:
+		PrintBoardError(MESSAGEMAIN_register_invalid_psw, MESSAGEMAIN_register_invalid_psw2,
+			HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+		break;
+	case PROFILE_CHK_ERROR_INVALID_PASSWORD_REP:
+		PrintBoardError(MESSAGEMAIN_register_invalid_n_psw, MESSAGEMAIN_register_invalid_n_psw2, 0);
+		break;
+	case PROFILE_CHK_ERROR_SHORT_PASSWORD:
+		PrintBoardError(MESSAGEMAIN_register_invalid_n_psw, MESSAGEMAIN_register_invalid_n_psw2, 0);
+		break;
+	case PROFILE_CHK_ERROR_INVALID_EMAIL:
+		PrintBoardError(MESSAGEMAIN_register_invalid_email, MESSAGEMAIN_register_invalid_email2, 0);
+		break;
+	case PROFILE_CHK_ERROR_CANNOT_DELETE_USR:
+		/* possible BUG here */
+		tmp = (char*)malloc(1000);
+		/*********************/
+		sprintf(tmp, MESSAGEMAIN_register_cannot_delete, ui->username);
+		PrintBoardError(tmp, MESSAGEMAIN_register_cannot_delete2,
+			HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+		free(tmp);
+		break;
+	default:
+		printhtmlerror();
+	}
+
+	if(err != PROFILE_CHK_ERROR_ALLOK)
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+}
+
+void printaccessdenied(char *deal)
+{
+	Tittle_cat(TITLE_Error);
+	PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+#if ENABLE_LOG > 2
+	print2log(LOG_UNKNOWN_URL, Cip, deal);
+#endif
+	PrintBoardError(MESSAGEMAIN_access_denied, MESSAGEMAIN_access_denied2, 0);
+	PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+}
+
+void printpassworderror(char *deal)
+{
+	/* incorrect username or password */
+#if ENABLE_LOG > 1
+	print2log(LOG_PSWDERROR, Cip, deal);
+#endif
+
+	Tittle_cat(TITLE_IncorrectPassword);
+				
+	/* incorrect login and/or password */
+	PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+	PrintBoardError(MESSAGEMAIN_incorrectpwd, MESSAGEMAIN_incorrectpwd2, 0);
+	PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+}
+
+void printnomessage(char *deal)
+{
+	Tittle_cat(TITLE_Error);
+#if ENABLE_LOG > 2
+	print2log(LOG_UNKNOWN_URL, Cip, deal);
+#endif
+	PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+	PrintBoardError(MESSAGEMAIN_nonexistingmsg, MESSAGEMAIN_nonexistingmsg2, 0);
+	PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+}
+
+void printbadurl(char *deal)
+{
+	Tittle_cat(TITLE_Error);
+
+#if ENABLE_LOG > 2
+	print2log(LOG_UNKNOWN_URL, Cip, deal);
+#endif
+	PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+	PrintBoardError(MESSAGEMAIN_requesterror, MESSAGEMAIN_requesterror2, 0);
+	PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+}
+
+/* print message thread */
+int PrintMessageThread(DB_Base *bd, DWORD root, DWORD Flag, DWORD Puser)
+{
+	// print admin toolbar
+	PrintAdminToolbar(root, Flag, Puser);
+
+	bd->DB_PrintMessageBody(root);
+	bd->DB_PrintMessageThread(root);
+	return 0;	
+}
+
+//rewritten for IIS compatibility
+// Return not more than maxlen bytes (including '\0')
+char* GetParams(DWORD maxlen)
+{
+	char* pCL = getenv("CONTENT_LENGTH");
+	if(pCL != NULL)
+	{
+		int nCL = atoi(pCL);
+		if(nCL > maxlen) nCL = maxlen;
+		if(nCL > 0)
+		{
+			DWORD ret;
+			char* szBuf = (char*)malloc(nCL + 3);
+			if(szBuf == NULL) {
+#if _DEBUG_ == 1
+				print2log("GetParams::malloc - out of memory");
+#endif
+				return NULL;
+			}
+			if((ret = (DWORD)fread(szBuf, sizeof(char), nCL, stdin)) == 0) {
+#if _DEBUG_ == 1
+				print2log("GetParams::fread - failed");
+#endif
+				goto cleanup;	
+			}
+			szBuf[ret] = '&';	// patch string for our parser
+			szBuf[ret+1] = '\0';
+//			print2log("POST params = %s, readed = %d", szBuf, ret);
+			return szBuf;
+cleanup:	
+			free(szBuf);
+		}
+	}
+	else {
+#if _DEBUG_ == 1
+		print2log("No CONTENT_LENGTH env. value");
+#endif
+	}
+	return NULL;
+}
+
+/* parse hex symbol to value */
+char inline parsesym(char s)
+{
+	s = (char)toupper(s);
+	if(s >= '0' && s <= '9') return (char)(s - '0');
+	if(s >= 'A' && s <= 'F') return (char)(s - 'A' + 10);
+	return 20;
+}
+
+/* find and return key [find] in string [par] between [find] and "&"
+* par is limited to MAX_PARAMETERS_LENGTH - 1
+*/
+char* strget(char *par,const char *find, WORD maxl, char end, bool argparsing)
+{
+	bool bZend = false;
+	char *res, *rres;
+	char *s, *x;
+	char a, b;
+	if(par == NULL) return NULL;
+	if(find == NULL) return NULL;
+	if((s = strstr(par, find)) == NULL) return NULL;
+	if(bZend = ((x = strchr(s, end)) == NULL))
+		x = strchr(s, 0);
+	else
+		*x = 0; // temporary change '&' to '\0'
+	rres = res = (char *)malloc(maxl + 1);
+	s = s + strlen(find);
+	if(argparsing) {
+		while(*s != '\0' && res - rres < maxl) {
+			if(*s == '%' && x > s + 2) {
+				if((a = parsesym(*(s + 1))) == 20) {
+					s++; continue; // ignore invalid %
+				}
+				if((b = parsesym(*(s + 2))) == 20) {
+					s++; continue; // ignore invalid %
+				}
+				*res = (char)(a*16 + b);
+				s+=2;
+			}
+			else if(*s == '+') *res = ' ';
+			else *res = *s;
+			res++;
+			s++;
+		}
+		*res = 0;
+		rres = (char*)realloc(rres, strlen(rres) + 1);
+	}
+	else {
+		strncpy(rres, s, maxl);
+		rres[maxl] = 0;	// fix for any string
+	}
+	if(!bZend)
+		*x = end;
+	return rres;
+}
+
+// get cookie information, if avaliable
+void ParseCookie()
+{
+	char *c, *s, *ss, *t, *st;
+	DWORD tmp;
+	int tmp_int;
+	
+	GlobalNewSession = 1;
+	currentft = 1;
+	currentlt = 1;
+	currentfm = 1;
+	currentlm = 1;
+	currentlann = 0;
+	
+	cookie_ss = CONFIGURE_SETTING_DEFAULT_ss;
+	cookie_tt = CONFIGURE_SETTING_DEFAULT_tt;
+	cookie_tv = CONFIGURE_SETTING_DEFAULT_tv;
+	cookie_tc = CONFIGURE_SETTING_DEFAULT_tc;
+	cookie_lsel = CONFIGURE_SETTING_DEFAULT_lsel;
+	cookie_dsm = CONFIGURE_SETTING_DEFAULT_dsm;
+	cookie_tz = DATETIME_DEFAULT_TIMEZONE;
+	
+#if	TOPICS_SYSTEM_SUPPORT
+	cookie_topics = CONFIGURE_SETTING_DEFAULT_topics;
+	topicsoverride = CONFIGURE_SETTING_DEFAULT_toverride;
+#endif
+
+	s = getenv("HTTP_COOKIE");
+	//if(s) print2log(s);
+	
+	if(s != NULL) {
+		c = (char*)malloc(strlen(s) + 1);
+		strcpy(c, s);
+
+		// After this strget() we will have all %XX parsed ! So we should
+		// disable %XX parsing
+		if((ss = strget(c, COOKIE_NAME_STRING, COOKIE_MAX_LENGTH, '&')) != NULL) {
+			ss = (char*)realloc(ss, strlen(ss)+2);
+			strcat(ss,"|");
+			
+			
+			if(t = strget(ss, "name=", AUTHOR_NAME_LENGTH - 1, '|', 0)){
+				cookie_name = t;
+			}
+
+			
+			if(t = strget(ss, "seq=", 30, '|', 0)){
+				cookie_seq = t;
+			}
+
+		
+			
+			if(t = strget(ss, "ed=", 20, '|', 0)) {
+				RefreshDate = strtol(t, &st, 10);
+				if((!((*t) != '\0' && *st == '\0')) || errno == ERANGE)
+				{
+					RefreshDate = 0;
+				}
+				free(t);
+			}
+
+
+			// read lsel (show type selection)
+			if(t = strget(ss, "lsel=", 3, '|', 0)) {
+				tmp = strtol(t, &st, 10);
+				if(( (*t) != '\0' && *st == '\0') && errno != ERANGE && tmp <= 2 && tmp >= 1)
+				{
+					cookie_lsel = tmp;
+				}
+				free(t);
+			}
+		
+			// read tc (thread count)
+			if(t = strget(ss, "tc=", 12, '|', 0)) {
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE && tmp > 0)
+				{
+					cookie_tc = tmp;
+				}
+				free(t);
+			}
+
+			// read tt (time type)
+			if(t = strget(ss, "tt=", 3, '|', 0)) {
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE && tmp <= 4 && tmp > 0)
+				{
+					cookie_tt = tmp;
+				}
+				free(t);
+			}
+				
+			// read ss (style string)
+			if(t = strget(ss, "ss=", 12, '|', 0)) {
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE && tmp > 0 && tmp <= 4)
+				{
+					cookie_ss = tmp;
+				}
+				free(t);
+			}
+		
+			// read tv (time value)
+			if(t  = strget(ss, "tv=", 12, '|', 0)) {
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE && tmp > 0)
+				{
+					cookie_tv = tmp;
+				}
+				free(t);
+			}
+
+			// read lt (last thread)
+			if(t = strget(ss, "lt=", 12, '|', 0)){
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE && tmp > 0)
+				{
+					currentlt = tmp;
+				}
+				free(t);
+			}
+					
+			// read fm (first message)
+			if(t = strget(ss, "ft=", 12, '|', 0)) {
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE && tmp > 0)
+				{
+					currentft = tmp;
+				}
+				free(t);
+			}
+				
+			// read lm (last message)
+			if(t = strget(ss, "lm=", 12, '|', 0)){
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE && tmp > 0)
+				{
+					currentlm = tmp;
+				}
+				free(t);
+			}
+			
+			// read fm (first message)
+			if(t = strget(ss, "fm=", 12, '|', 0)){
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE && tmp > 0)
+				{
+					currentfm = tmp;
+				}
+				free(t);
+			}
+			
+			// read dsm (globally disable smiles, picture, and 2-d link bar)
+			if(t = strget(ss, "dsm=", 12, '|', 0)) {
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE && tmp > 0)
+				{
+				cookie_dsm = tmp;
+				}
+				free(t);
+			}
+			
+#if	TOPICS_SYSTEM_SUPPORT
+			// read topics
+			if(t = strget(ss, "topics=", 20, '|', 0)) {
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE)
+				{
+				cookie_topics = tmp;
+				}
+				free(t);
+			}
+
+			// read topics override
+			if(t = strget(ss, "tovr=", 12, '|', 0)) {
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE)
+				{
+				topicsoverride = tmp;
+				}
+				free(t);
+			}
+#endif
+
+			// read lann (last hided announce)
+			if(t = strget(ss, "lann=", 12, '|', 0)) {
+				tmp = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE && tmp >= 0)
+				{
+				currentlann = tmp;
+				ReadLastAnnounceNumber(&tmp);
+				if(currentlann > tmp) currentlann = tmp;
+				}
+				free(t);
+			}
+			
+			// read timezone
+			if(t = strget(ss, "tz=", 12, '|', 0) ) {
+				tmp_int = strtol(t, &st, 10);
+				if(((*t) != '\0' && *st == '\0') && errno != ERANGE && tmp_int >= -12 && tmp_int <= 12)
+				{
+					cookie_tz = tmp_int;
+				}
+				free(t);
+			}
+
+			free(ss);
+	
+		}
+		
+	
+		if((ss = strget(c, COOKIE_SESSION_NAME, 12, '&')) && strcmp(ss, "on") == 0) {
+			GlobalNewSession = 0;
+			free(ss);
+		}
+			
+		free(c);
+	}
+
+	if(!cookie_name){
+		cookie_name = (char*)malloc(1);
+		cookie_name[0] = 0;
+	}
+	
+	if(!cookie_seq) {
+		cookie_seq = (char*)malloc(1);
+		cookie_seq[0] = 0;
+	}
+}
+
+// calculate time limit for printing messages
+void calc_print_time()
+{
+	if(currentlsel == 1) {
+		// calculate time limit
+		current_minprntime = time(NULL);
+		switch(currenttt) {
+		case 1:
+			// hours
+			current_minprntime = current_minprntime - 3600*currenttv;
+			break;
+		case 2:
+			// days
+			current_minprntime = current_minprntime - 3600*24*currenttv;
+			break;
+		case 3:
+			// weeks
+			current_minprntime = current_minprntime - 3600*24*7*currenttv;
+			break;
+		case 4:
+			// months
+			current_minprntime = current_minprntime - 3600*24*31*currenttv;
+			break;
+		}
+	}
+}
+
+static void PrepareActionResult(int action, char **c_par1, char **c_par2)
+{
+	switch(action) {
+	case MSG_CHK_ERROR_NONAME :
+		*c_par1 = MESSAGEMAIN_add_no_name;
+		*c_par2 = MESSAGEMAIN_add_no_name2;
+		break;
+	case MSG_CHK_ERROR_NOMSGHEADER:
+		*c_par1 = MESSAGEMAIN_add_no_subject;
+		*c_par2 = MESSAGEMAIN_add_no_subject2;
+		break;
+	case MSG_CHK_ERROR_NOMSGBODY:
+		*c_par1 = MESSAGEMAIN_add_no_body;
+		*c_par2 = MESSAGEMAIN_add_no_body2;
+		break;
+	case MSG_CHK_ERROR_BADSPELLING:
+		*c_par1 = MESSAGEMAIN_add_spelling;
+		*c_par2 = MESSAGEMAIN_add_spelling2;
+		break;
+#if BANNED_CHECK
+	case MSG_CHK_ERROR_BANNED:
+		*c_par1 = MESSAGEMAIN_add_banned;
+		*c_par2 = MESSAGEMAIN_add_banned2;
+		break;
+#endif
+	case MSG_CHK_ERROR_CLOSED:
+		*c_par1 = MESSAGEMAIN_add_closed;
+		*c_par2 = MESSAGEMAIN_add_closed2;
+		break;
+	case MSG_CHK_ERROR_INVALID_REPLY:
+		*c_par1 = MESSAGEMAIN_add_invalid_reply;
+		*c_par2 = MESSAGEMAIN_add_invalid_reply;
+		break;
+	case MSG_CHK_ERROR_INVALID_PASSW:
+		*c_par1 = MESSAGEMAIN_incorrectpwd;
+		*c_par2 = MESSAGEMAIN_incorrectpwd2;
+		break;
+	default:
+		*c_par1 = MESSAGEMAIN_unknownerr;
+		*c_par2 = MESSAGEMAIN_unknownerr2;
+		break;
+	}
+}
+
+int ConvertHex(char *s, char *res)
+{
+	int i = 0;
+	if(!s) return 0;
+	while(*s != 0 && *(s+1) != 0) {
+#define FROM_HEX(x) ((x >= 'A' && x <= 'F') ? (x-'A' + 10) : \
+	(x >= 'a' && x <= 'f') ? (x-'a' + 10) : (x - '0'))
+		res[i] = FROM_HEX(*s)*16 + FROM_HEX(*(s+1));
+		i++;
+		s+=2;
+	}
+	return i;
+}
+
+int main()
+{
+	char *deal, *st, *mesb;
+	char *par; // parameters string
+	char *tmp;
+	int initok = 0;
+	DB_Base DB;
+	SMessage mes;
+
+#ifndef WIN32
+
+	if(!isEnoughSpace()) {
+		printf("Content-type: text/html\n\n"
+		"Sorry guys, no space left for DB - wwwconf shutting down.");
+		exit(1);
+	}
+
+#endif
+
+#ifdef RT_REDIRECT
+#define BADURL "/board/"
+#define GOODURL "http://board.rt.mipt.ru/"
+	if((st = getenv(REQUEST_URI)) != NULL)
+	{
+		deal = (char*)malloc(strlen(st) + 2);
+		strcpy(deal, st);
+		//fprintf(stderr,"req uri: %s\n",deal);
+		if (strncmp(deal, BADURL, strlen(BADURL)) == 0 ) { 
+			tmp = (char*)malloc(strlen(deal) + strlen(GOODURL) + 10);
+			sprintf(tmp,"%s%s",GOODURL,deal + strlen(BADURL));
+			//fprintf(stderr,"redir: %s\n",tmp);
+			HttpRedirect(tmp);
+			free(tmp);
+			goto End_part;
+		}	
+		free(deal);
+	}
+#endif
+
+#define UA_LINKS	"Links"
+#define UA_LYNX		"Lynx"
+#define UA_NN202	"Mozilla/2.02"
+	// will we use <DIV> or <DL>?
+	if( ((st = getenv("HTTP_USER_AGENT")) != NULL) && (*st != '\0') )
+	{
+		deal = (char*)malloc(strlen(st) + 2);
+		strcpy(deal, st);
+		if ( (strncmp(deal, UA_LINKS, strlen(UA_LINKS)) == 0) ||
+			 (strncmp(deal, UA_LYNX,  strlen(UA_LYNX))  == 0) ||
+			 (strncmp(deal, UA_NN202, strlen(UA_NN202)) == 0) ) {
+			strcpy(DESIGN_open_dl, DESIGN_OP_DL);
+			strcpy(DESIGN_open_dl_grey, DESIGN_OP_DL);
+			strcpy(DESIGN_open_dl_white, DESIGN_OP_DL);
+			strcpy(DESIGN_close_dl, DESIGN_CL_DL);
+			strcpy(DESIGN_break, DESIGN_DD);
+			strcpy(DESIGN_threads_divider, DESIGN_THREADS_DIVIDER_HR);
+			initok = 1;
+		}
+		free(deal);
+	}
+	if (!initok) {
+			strcpy(DESIGN_open_dl, DESIGN_OP_DIV);
+			strcpy(DESIGN_open_dl_grey, DESIGN_OP_DIV_grey);
+			strcpy(DESIGN_open_dl_white, DESIGN_OP_DIV_white);
+			strcpy(DESIGN_close_dl, DESIGN_CL_DIV);
+			strcpy(DESIGN_break, DESIGN_BR);
+			strcpy(DESIGN_threads_divider, DESIGN_THREADS_DIVIDER_IMG);
+	}
+
+#if defined(WIN32) && defined(IP_TO_HOSTNAME_RESOLVE)
+
+	WSADATA wsaData;
+	if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0 ) {
+		// Tell the user that we could not find a usable
+		// WinSock DLL, but here just do nothing and bailing out
+		return -1;
+	}
+
+#endif
+
+	/*
+	// -----------------------------
+	char *s = (char *)&mes;
+	for(int i=0;i<sizeof(SMessage);i++) s[i]=0;
+	s = (char *)&mbody;
+	for(i=0;i<sizeof(SMessageBody);i++) s[i]=0;
+	strcpy(mes.AuthorName,"www");
+	strcpy(mes.MessageHeader,"1111111");
+	strcpy(mes.HostName,"194.85.83.213");
+	char sx[100] = "[i][code];))111 ;)serial[url=http:\\www.ru]serial[/url][code]";
+	i = DB.DB_InsertMessage(&mes, 0, strlen(sx), sx, &mbody, 0xFFFFFFF, "www");
+	goto End_part;
+	// -----------------------------
+	*/
+
+#if USE_LOCALE
+	/* set locale */
+	setlocale(LC_ALL, LANGUAGE_LOCALE);
+#endif
+
+	/* get cookie string, if available, and parse it */
+	ParseCookie();
+	
+
+#if STABLE_TITLE == 0
+	// set default title
+	ConfTitle = (char*)malloc(strlen(TITLE_WWWConfBegining) + 1);
+	strcpy(ConfTitle, TITLE_WWWConfBegining);
+#endif
+
+
+
+	// get parameters with we have been run
+	if((st = getenv(QUERY_STRING)) != NULL)
+	{
+		deal = (char*)malloc(strlen(st) + 2);
+		strcpy(deal, st);
+	}
+	else deal = NULL;
+	
+	if(deal == NULL || (strcmp(deal,"") == 0))
+	{
+		deal = (char*)malloc(20);
+		strcpy(deal,"index");
+	}
+
+	// detect IP
+	if((tmp = getenv(REMOTE_ADDR)) != NULL)
+	{
+		Cip = (char*)malloc(strlen(tmp) + 1);
+		strcpy(Cip, tmp);
+	}
+	else {
+		Cip = (char*)malloc(strlen(TAG_IP_NOT_DETECTED) + 1);
+		strcpy(Cip, TAG_IP_NOT_DETECTED);
+	}
+
+	// translate IP
+	// if it fails, we will have Nip = 0
+	char *tst, *tms;
+	tst = Cip;
+	{
+		for(register DWORD i = 0; i < 4; i++)
+		{
+			if((tms = strchr(tst,'.')) != NULL || (tms = strchr(tst,'\0')) != NULL)
+			{
+				*tms = '\0';
+				((char*)(&Nip))[i] = (unsigned char)atoi(tst);
+				tst = tms + 1;
+				if(i < 3) *tms = '.';
+			}
+			else break;
+		}
+	}
+	if(Nip == 0) Nip = 1;
+
+#if ACTIVITY_LOGGING_SUPPORT
+	// user activity logging
+	DWORD hostcnt, hitcnt;
+	RegisterActivityFrom(Nip, hitcnt, hostcnt);
+#endif
+
+#if _DEBUG_ == 1
+	//	print2log("Entering from : %s, deal=%s", Cip, deal);
+#endif
+	
+	strcat(deal,"&");
+
+	/************ get user info from session ************/
+	{
+		DWORD tmp[2];
+		if(strlen(cookie_seq) == 16 &&
+			ConvertHex(cookie_seq, (char*)&tmp) == 8)
+		{
+			tmp[0] = ntohl(tmp[0]);	// use network order due printf()
+			tmp[1] = ntohl(tmp[1]);
+			// if session code not zero let's open session
+			if(tmp[0] != 0 && tmp[1] != 0)
+			{
+				// try to open sequence
+				if(ULogin.CheckSession(tmp, Nip, 0))
+					strcpy(cookie_name, ULogin.pui->username);
+			}
+		}
+	}
+	
+	//	
+	// checking settings were saved in profile or cookies and  restoring them.
+	//
+
+	if(ULogin.LU.ID[0] && (ULogin.pui->Flags & PROFILES_FLAG_VIEW_SETTINGS)  ) { 
+
+		currentdsm = ULogin.pui->vs.dsm;
+		currenttopics = ULogin.pui->vs.topics;
+		currenttv = ULogin.pui->vs.tv;
+		currenttc = ULogin.pui->vs.tc;
+		currentss = ULogin.pui->vs.ss;
+		currentlsel = ULogin.pui->vs.lsel;
+		currenttt = ULogin.pui->vs.tt;
+		currenttz = ULogin.pui->vs.tz;
+	}
+	else{
+		currentlsel = cookie_lsel;
+		currenttc = cookie_tc;
+		currenttt = cookie_tt;
+		currenttv = cookie_tv;
+		currentss = cookie_ss;
+		currentdsm = cookie_dsm;
+		currenttopics = cookie_topics;
+		currenttz = cookie_tz;
+	}
+
+	// caluclate minimal message print time
+	calc_print_time();
+
+
+	//security check
+	if(ULogin.LU.ID[0] && (ULogin.LU.right & USERRIGHT_SUPERUSER) )
+		print2log("Superuser: %s from %s - %s", ULogin.pui->username, Cip, deal);
+
+
+	//==========================	
+	// detecting user wishes %)
+	//==========================
+	
+	
+	
+	if(strncmp(deal, "resetnew", 8) == 0) {
+		// apply old last message value
+		currentlm = currentfm;
+		currentlt = currentft;
+		cookie_lastenter =  time(NULL);
+		// set new read time value
+		PrintHTMLHeader(HEADERSTRING_REDIRECT_NOW | HEADERSTRING_NO_CACHE_THIS, MAINPAGE_INDEX);
+		
+		goto End_part;
+	}
+
+	if(strncmp(deal, "index", 5) == 0)
+	{
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_VIEW_MESSAGE) == 0)
+		{
+			printaccessdenied(deal);
+			goto End_part;
+		}
+
+		if((st = strget(deal,"index=", 16, '&')) != NULL)
+		{
+			int entok = 0;
+			if(strcmp(st, "all") == 0) {
+				topicsoverride = TOPICS_COUNT + 50;
+				entok = 1;
+			}
+			else {
+				errno = 0;
+				char *ss;
+				DWORD tmp = strtol(st, &ss, 10);
+				if((!(*st != '\0' && *ss == '\0')) || errno == ERANGE || tmp > TOPICS_COUNT)
+				{
+					// just print common index
+				}
+				else {
+					topicsoverride = tmp;
+					entok = 1;
+				}
+			}
+			if(entok) {
+				PrintHTMLHeader(HEADERSTRING_REDIRECT_NOW | HEADERSTRING_NO_CACHE_THIS, MAINPAGE_INDEX);
+				goto End_part;
+			}
+		}
+
+#if TOPIC_SYSTEM_SUPPORT
+#if STABLE_TITLE == 0
+		// add current topic to index title
+		if (topicsoverride > 0 && topicsoverride <= TOPICS_COUNT) {
+			Tittle_cat(Topics_List[topicsoverride-1]);
+		} else if (topicsoverride > (TOPICS_COUNT + 1)) {
+			Tittle_cat(MESSAGEMAIN_WELCOME_ALLTOPICS);
+		}
+#endif
+#endif
+
+
+		//	Apply new last message and thread value
+		DWORD readed = DB.VIndexCountInDB();
+		DWORD mtc;
+		//	Read main threads count
+		if(!DB.ReadMainThreadCount(&mtc)) mtc=0;
+		
+		currentfm = readed;
+		currentft = mtc;
+		//
+		//	Here we make a decision about new session of "+"
+		//
+		if(GlobalNewSession)
+		{
+			// apply old last message value
+			currentlm = currentfm;
+			currentlt = currentft;
+			// set new read time value
+			cookie_lastenter = time(NULL);
+		}
+
+
+		PrintHTMLHeader(HEADERSTRING_REG_USER_LIST | HEADERSTRING_POST_NEW_MESSAGE |
+			HEADERSTRING_CONFIGURE | HEADERSTRING_WELCOME_INFO |
+			HEADERSTRING_ENABLE_RESETNEW | HEADERSTRING_DISABLE_END_TABLE, MAINPAGE_INDEX);
+
+		//	Prepare information about new message count and dispaly mode */
+		char displaymode[500];		// display message mode
+		char displaynewmsg[500];	// new message info
+		char topicselect[2000];		// topic select: MAYBE BUG HERE IF TOO MANY TOPICS
+		char privmesinfo[500];		// private message info
+		char activityloginfo[500];	// user activity info
+		topicselect[0] = 0;
+		privmesinfo[0] = 0;
+		activityloginfo[0] = 0;
+
+		DWORD a = currentfm - currentlm;
+		DWORD t = ((currentft - currentlt) >= 0) ? (currentft - currentlt) : 0;
+		DWORD totalcount = DB.MessageCountInDB();
+		if(a) sprintf(displaynewmsg, MESSAGEMAIN_WELCOME_NEWTHREADS, t, a, totalcount);
+		else sprintf(displaynewmsg, MESSAGEMAIN_WELCOME_NONEWTHREADS, totalcount);
+
+		// current settings in welcome message
+		if(currentlsel == 1)
+		{
+			// hours
+			sprintf(displaymode, MESSAGEMAIN_WELCOME_DISPLAYTIME, currenttv, MESSAGEHEAD_timetypes[currenttt-1]);
+		}
+		else
+		{
+			// threads
+			sprintf(displaymode, MESSAGEMAIN_WELCOME_DISPLAYTHREADS, currenttc);
+		}
+
+#if	TOPICS_SYSTEM_SUPPORT
+		{
+		char tmp[500], sel[50], sel2[50];
+		sel[0] = sel2[0] = 0;
+		//	Prepare topic list
+		if(topicsoverride == 0) strcpy(sel, LISTBOX_SELECTED);
+		if(topicsoverride > TOPICS_COUNT) strcpy(sel2, LISTBOX_SELECTED);
+		sprintf(topicselect, DESIGN_WELCOME_QUICKNAV, sel, MESSAGEMAIN_WELCOME_YOURSETTINGS, sel2, MESSAGEMAIN_WELCOME_ALLTOPICS);
+		for(DWORD i = 0; i < TOPICS_COUNT; i++) {
+			if(Topics_List_map[i] == (topicsoverride - 1)) strcpy(sel, LISTBOX_SELECTED);
+			else sel[0] = 0; // ""
+			sprintf(tmp, "<OPTION VALUE=\"?index=%d\"%s>%s</OPTION>\n", Topics_List_map[i]+1, sel, Topics_List[Topics_List_map[i]]);
+			strcat(topicselect, tmp);
+		}
+		strcat(topicselect, "</SELECT>");
+		}
+#endif
+
+		// moved to PrintTopStaticLinks //printf("<TR><TD class=cl>&nbsp;</TD></TR>");
+		
+		// print info about personal messages
+		if(ULogin.LU.ID[0] != 0 && ULogin.pui->persmescnt - ULogin.pui->readpersmescnt > 0) {
+			sprintf( privmesinfo, ", <A HREF=\"" MY_CGI_URL "?persmsg\" STYLE=\"text-decoration:underline;\"><FONT COLOR=RED>" MESSAGEMAIN_privatemsg_newmsgann " %ld " \
+			MESSAGEMAIN_privatemsg_newmsgann1 "</FONT></A>", (ULogin.pui->persmescnt - ULogin.pui->readpersmescnt) );
+		}
+
+#if ACTIVITY_LOGGING_SUPPORT
+		sprintf(activityloginfo, MESSAGEMAIN_ACTIVITY_STATVIEW, hitcnt, hostcnt);
+#endif
+
+		int formstarted = 0;
+		if(ULogin.LU.ID[0] == 0) {
+			printf(MESSAGEMAIN_WELCOME_START, PROFILES_MAX_USERNAME_LENGTH,
+				FilterHTMLTags(cookie_name, 1000, 0),
+				PROFILES_MAX_PASSWORD_LENGTH, displaynewmsg, displaymode,
+				activityloginfo, topicselect);
+			formstarted = 1;
+		}
+		else {
+			char uname[1000];
+			DB.Profile_UserName(ULogin.pui->username, uname, 1);
+			printf(MESSAGEMAIN_WELCOME_LOGGEDSTART, uname, privmesinfo, displaynewmsg,
+				displaymode, activityloginfo, topicselect);
+		}
+
+
+		
+		// Announce going here
+		{
+			SGlobalAnnounce *ga;
+			DWORD cnt, i;
+			if(ReadGlobalAnnounces(0, &ga, &cnt) != ANNOUNCES_RETURN_OK) printhtmlerror();
+			if(cnt) {
+				char uname[1000], del[1000], date[100];
+				int something_printed = 0;
+				for(i = 0; i < cnt; i++) {
+					if(ga[i].Number > currentlann) {
+						DB.Profile_UserName(ga[i].From, uname, 1);
+
+						char *st = FilterHTMLTags(ga[i].Announce, MAX_PARAMETERS_STRING - 1);
+						char *st1 = NULL;
+						DWORD retflg;
+						if(FilterBoardTags(st, &st1, 0, MAX_PARAMETERS_STRING - 1, 
+							MESSAGE_ENABLED_SMILES | MESSAGE_ENABLED_TAGS | BOARDTAGS_PURL_ENABLE |
+							BOARDTAGS_EXPAND_ENTER, &retflg) == 0)
+						{
+							st1 = st;
+							st = NULL;
+						}
+
+						if(((ULogin.LU.right & USERRIGHT_POST_GLOBAL_ANNOUNCE) != 0 && ga[i].UIdFrom ==
+							ULogin.LU.UniqID) || (ULogin.LU.right & USERRIGHT_SUPERUSER) != 0)
+						{
+							sprintf(del, "<A HREF=\"" MY_CGI_URL "?ganndel=%d\" "
+								"STYLE=\"text-decoration:underline;\">" MESSAGEMAIN_globann_delannounce
+								"</A> <A HREF=\"" MY_CGI_URL "?globann=%d\" "
+								"STYLE=\"text-decoration:underline;\">" MESSAGEMAIN_globann_updannounce
+								"</A>", ga[i].Number, ga[i].Number);
+					}	
+						else del[0] = 0;
+
+						ConvertTime(ga[i].Date, date);
+
+						if(!something_printed) {
+							if(!formstarted) printf("<BR>");
+							else printf("</FORM>");
+						}
+
+						printf(DESIGN_GLOBALANN_FRAME, DESIGN_open_dl, st1, MESSAGEMAIN_globann_postedby,
+							uname, date, del, DESIGN_close_dl);
+
+						if(st) free(st);
+						if(st1) free(st1);
+						something_printed = 1;
+					}
+				}
+				if(something_printed) {
+					printf("<CENTER><A HREF=\"?rann=%d\" STYLE=\"text-decoration:underline;\" class=cl>" MESSAGEMAIN_globann_hidenewann "</A></CENTER><BR>", ga[cnt-1].Number);
+				}
+				else {
+					// show all announces
+					printf("<CENTER><A HREF=\"?rann=0\" STYLE=\"text-decoration:underline;\" class=cl>" MESSAGEMAIN_globann_showall "(%d)</A></CENTER><BR>", cnt);
+					// gap between welcome header and messages
+					if(formstarted) printf("</FORM>");
+					else printf(DESIGN_INDEX_WELCOME_CLOSE);
+				}
+			}
+			else {
+				// gap between welcome header and messages
+				if(formstarted) printf("</FORM>");
+				else printf(DESIGN_INDEX_WELCOME_CLOSE);
+			}
+			if(ga) free(ga);
+		} // of announces
+
+		DWORD oldct = currenttopics;
+		
+		if(topicsoverride) {
+			if(topicsoverride > TOPICS_COUNT) currenttopics = 0xffffffff;	// all
+			else currenttopics = (1<<(topicsoverride-1));
+		}
+		DB.DB_PrintHtmlIndex(time(NULL), time(NULL), mtc);
+		currenttopics = oldct;
+		PrintBottomLines(HEADERSTRING_REG_USER_LIST | HEADERSTRING_POST_NEW_MESSAGE | HEADERSTRING_CONFIGURE | HEADERSTRING_ENABLE_RESETNEW, MAINPAGE_INDEX);
+		goto End_part;
+	}
+	
+	if(strncmp(deal, "read", 4) == 0)
+	{
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_VIEW_MESSAGE) == 0)
+		{
+			printaccessdenied(deal);
+			goto End_part;
+		}
+
+		if((st = strget(deal,"read=", 16, '&')) != NULL)
+		{
+			errno = 0;
+			char *ss;
+			DWORD tmp = strtol(st, &ss, 10);
+			DWORD x;
+			if((!(*st != '\0' && *ss == '\0')) || errno == ERANGE ||
+				tmp < 1 || (x = DB.TranslateMsgIndex(tmp)) == NO_MESSAGE_CODE)
+			{
+				printnomessage(deal);
+			}
+			else
+			{
+				// read message
+				if(!ReadDBMessage(x, &mes)) printhtmlerror();
+
+				/* allow read invisible message only to SUPERUSER */
+				if((mes.Flag & MESSAGE_IS_INVISIBLE) && ((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0)) {
+					printnomessage(deal);
+				}
+				else
+				{
+#if STABLE_TITLE == 0
+					// change title
+					char *an;
+					DWORD xtmp;
+					if(FilterBoardTags(mes.MessageHeader, &an, mes.SecHeader,
+						MAX_PARAMETERS_STRING, MESSAGE_ENABLED_TAGS | BOARDTAGS_CUT_TAGS, &xtmp) != 1)
+					{
+						an = (char*)&(mes.MessageHeader);
+					}
+					if (mes.Topics < TOPICS_COUNT && mes.Topics  != 0 ){
+						char *t;
+						t = (char*)malloc(strlen(an) + strlen(TITLE_divider) + strlen(Topics_List[mes.Topics]) + 4);
+						*t = 0;
+						strcat(t, Topics_List[mes.Topics]);
+						strcat(t, TITLE_divider);
+						strcat(t, an);
+						Tittle_cat(t);
+						free(t);
+					} else 
+						Tittle_cat(an);
+
+					if(an != (char*)&(mes.MessageHeader)) free(an);
+#endif
+					// tmpxx contains vindex of parent message if thread is rolled.
+					// if some sub-thread is rolled, tmpxx contains vindex of MAIN parent of thread
+					
+					DWORD tmpxx;
+					if (mes.Flag & MESSAGE_COLLAPSED_THREAD && mes.Level > 0){
+						SMessage parmes;
+						if(!ReadDBMessage(mes.ParentThread, &parmes)) printhtmlerror();
+						tmpxx = parmes.ViIndex;
+					}
+					else tmpxx = tmp;
+
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_ENABLE_TO_MESSAGE |
+						((currentdsm & 0x100) ? HEADERSTRING_ENABLE_REPLY_LINK : 0), tmpxx, tmp);
+					
+					PrintMessageThread(&DB, tmp, mes.Flag, mes.UniqUserID);
+
+					/* allow post to closed message only to SUPERUSER and USER  */
+					if( (((mes.Flag & MESSAGE_IS_CLOSED) == 0 &&
+						(ULogin.LU.right & USERRIGHT_CREATE_MESSAGE) )  ||
+						(ULogin.LU.right & USERRIGHT_SUPERUSER) != 0 ) && 
+						((currentfm < MAX_DELTA_POST_MESSAGE) || 
+						(tmp > (currentfm - MAX_DELTA_POST_MESSAGE)) || 
+						(tmp == 0)) && ((currentdsm & 0x100) == 0))
+					{
+						strcpy(mes.AuthorName, cookie_name);
+						mes.MessageHeader[0] = 0;
+						mesb = (char*)malloc(1);
+						*mesb = 0;
+						PrintMessageForm(&mes, mesb, tmp, ACTION_BUTTON_POST | ACTION_BUTTON_PREVIEW | ACTION_BUTTON_FAKEREPLY);
+						free(mesb);
+					}
+
+					PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_ENABLE_TO_MESSAGE, tmpxx, tmp);
+				}
+			}
+			free(st);
+		}
+		else goto End_URLerror;
+		goto End_part;
+	}
+	
+	if(strncmp(deal, "form", 4) == 0)
+	{
+		DWORD repnum = 0;
+		
+		// read form= parameter (if reply form is required)
+		if((st = strget(deal,"form=", 16, '&')) != NULL)
+		{
+			errno = 0;
+			char *ss;
+			repnum = strtol(st, &ss, 10);
+			DWORD x;
+			if((!(*st != '\0' && *ss == '\0')) || errno == ERANGE ||
+				repnum < 1 || (x = DB.TranslateMsgIndex(repnum)) == NO_MESSAGE_CODE)
+			{
+				printnomessage(deal);
+				free(st);
+				goto End_part; 
+			}
+			free(st);
+		}
+
+		/* security check */
+		if( (repnum && (ULogin.LU.right & USERRIGHT_CREATE_MESSAGE) == 0 ) ||
+			( !repnum && (ULogin.LU.right & USERRIGHT_CREATE_MESSAGE_THREAD) == 0) ){
+				printaccessdenied(deal);
+				goto End_part;
+		}
+		
+		if(!repnum) Tittle_cat(TITLE_Form);
+		else Tittle_cat(TITLE_WriteReply);
+
+		PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+		
+		strcpy(mes.AuthorName, FilterHTMLTags(cookie_name, 1000, 0));
+		mes.MessageHeader[0] = 0;
+		mesb = (char*)malloc(1);
+		*mesb = 0;
+		PrintMessageForm(&mes, mesb, repnum,
+			repnum ? ACTION_BUTTON_POST | ACTION_BUTTON_PREVIEW | ACTION_BUTTON_FAKEREPLY :
+			ACTION_BUTTON_POST | ACTION_BUTTON_PREVIEW);
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+		goto End_part;
+	}
+	
+	
+	if(strncmp(deal, "xpost", 5) == 0) {
+		char *ss = NULL;
+		char *passw, *mb, *c_host;
+		DWORD ROOT = 0;
+		DWORD CFlags = 0, LogMeIn = 0;
+
+		// read method GET post params
+		if((ss = strget(deal, "xpost=", 16, '&')) != NULL ) {
+			errno = 0;
+			char *st;
+			ROOT = strtol(ss, &st, 10);
+			if((!(*ss != '\0' && *st == '\0')) || errno == ERANGE ||
+				(ROOT != 0 && DB.TranslateMsgIndex(ROOT) == NO_MESSAGE_CODE)) {
+				printnomessage(deal);
+				goto End_part;
+			}
+			free(ss);
+		}
+		else {
+			printbadurl(deal);
+			goto End_part;
+		}
+
+		// Check security rights
+		if(! ((ULogin.LU.right & USERRIGHT_CREATE_MESSAGE) && ROOT) &&
+			!((ULogin.LU.right & USERRIGHT_CREATE_MESSAGE_THREAD) && ROOT == 0))
+		{
+			printaccessdenied(deal);
+			goto End_part;
+		}
+			
+			
+		// make IP address
+		if ((tmp = getenv("HTTP_X_FORWARDED_FOR")) != NULL) print2log("proxy %s - %s", tmp, deal);
+		if(Nip != 1) {
+		/*	// resolve
+			char*tmp;
+			// Exception! if forwareder for localhost or 127.0.0.1 - ignore forwarder
+			if((tmp = getenv("HTTP_X_FORWARDED_FOR")) != NULL &&
+				strcmp(tmp, "127.0.0.1") != 0 && strcmp(tmp, "localhost") != 0 &&
+				strncmp(tmp, "192.168", 7) != 0 && strncmp(tmp, "10.", 3) != 0)
+			{
+				// TODO: more detailed log here
+				print2log("proxy %s - %s", tmp, deal);
+				
+				// TODO: we need to resolve DNS here
+				strncpy(mes.HostName, tmp, HOST_NAME_LENGTH - 1);
+				mes.HostName[HOST_NAME_LENGTH - 1] = 0;
+			} else
+		*/ 
+			if(!IP2HostName(Nip, mes.HostName, HOST_NAME_LENGTH - 1))
+				strcpy(mes.HostName, Cip);
+		}
+		else strcpy(mes.HostName, TAG_IP_NOT_DETECTED);
+		mes.IPAddr = Nip;
+
+#if HTTP_REFERER_CHECK == 1
+		char *useragent = getenv("HTTP_USER_AGENT");
+		if(
+			!useragent || 
+			(strncmp(useragent, UA_LYNX, strlen(UA_LYNX)) &&
+			strncmp(useragent, UA_LINKS, strlen(UA_LINKS)))
+		) {
+			char *tts = getenv("HTTP_REFERER");
+			if(tts == NULL || strstr(tts, ALLOWED_HTTP_REFERER) == NULL) {
+				// TODO: more detailed error here
+				print2log("bad referer, tts='%s'", tts);
+				printbadurl(deal);
+				goto End_part;
+			}
+		}
+#endif
+
+		// get parameters
+		par = GetParams(MAX_PARAMETERS_STRING);
+
+		// read name
+		st = strget(par,"name=",  AUTHOR_NAME_LENGTH - 1, '&');
+		if(st == NULL) {
+			strcpy(mes.AuthorName, "");
+		}
+		else {
+			strncpy(mes.AuthorName, st, AUTHOR_NAME_LENGTH - 1);
+			mes.AuthorName[AUTHOR_NAME_LENGTH - 1] = 0;
+			free(st);
+		}
+		
+		// read password
+		passw = strget(par,"pswd=", PROFILES_MAX_PASSWORD_LENGTH - 1, '&');
+
+		// read subject
+		st = strget(par,"subject=", MESSAGE_HEADER_LENGTH - 1, '&');
+		if(st == NULL) {
+			strcpy(mes.MessageHeader, "");
+		}
+		else {
+			strncpy(mes.MessageHeader, FilterWhitespaces(st), MESSAGE_HEADER_LENGTH - 1);
+			mes.MessageHeader[MESSAGE_HEADER_LENGTH - 1] = 0;
+			free(st);
+		}
+
+		// read host (for edit)
+		c_host = strget(par,"host=", HOST_NAME_LENGTH - 1, '&');
+
+		// read msg body
+		mesb = strget(par,"body=", MAX_PARAMETERS_STRING, '&');
+		// this is needed because of char #10 filtering.
+		// in WIN32 printf() works incorrectly with it
+#if defined(WIN32)
+		FilterMessageForPreview(mesb, &mb);
+		free(mesb);
+		mesb = mb;
+#endif
+		
+		// read dct (disable WWWConf Tags)
+		st = strget(par,"dct=", 10, '&');
+		if(st != NULL) {
+			if(strcmp(st, "on") == 0) {
+				CFlags = CFlags | MSG_CHK_DISABLE_WWWCONF_TAGS;
+			}
+			free(st);
+		}
+		
+		// read dst (disable smile codes)
+		st = strget(par,"dst=", 10, '&');
+		if(st != NULL) {
+			if(strcmp(st, "on") == 0) {
+				CFlags = CFlags | MSG_CHK_DISABLE_SMILE_CODES;
+			}
+			free(st);
+		}
+		
+		// read wen (acknol. by email)
+		st = strget(par,"wen=", 10, '&');
+		if(st != NULL) {
+			// mail ackn. allowed ONLY for threads with ROOT == 0
+			if(strcmp(st, "on") == 0 && ROOT == 0) {
+				CFlags = CFlags | MSG_CHK_ENABLE_EMAIL_ACKNL;
+			}
+			free(st);
+		}
+
+		// read lmi (login me)
+		st = strget(par,"lmi=", 10, '&');
+		if(st != NULL) {
+			if(strcmp(st, "on") == 0) {
+				LogMeIn = 1;
+			}
+			free(st);
+		}
+
+		mes.Topics = 0;
+#if TOPICS_SYSTEM_SUPPORT
+		{
+			char *ss;
+			DWORD topicID;
+			if((ss = strget(par, "topic=", 10, '&')) != NULL) {
+				errno = 0;
+				char *st;
+				topicID = strtol(ss, &st, 10);
+				if((!(*ss != '\0' && *st == '\0')) || errno == ERANGE || topicID > TOPICS_COUNT - 1)
+				{
+					// default topic
+					mes.Topics = TOPICS_DEFAULT_SELECTED;
+				}
+				mes.Topics = topicID;
+				free(ss);
+			}
+		}
+#endif
+
+		// get user action (post/edit/preview)
+		int action = getAction(par);
+		free(par);
+
+		// init current error
+		int cr = 0;
+		switch(action) {
+		case ACTION_POST:
+			{
+				//*************************************************
+				//	post message
+				//*************************************************
+
+				// antispam
+				if(CheckPostfromIPValidity(Nip, POST_TIME_LIMIT) == 0) {
+#if ENABLE_LOG
+					print2log(LOG_SPAM_TRY, Cip, deal);
+#endif
+					Tittle_cat(TITLE_Spamtry);
+
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					PrintBoardError(MESSAGEMAIN_spamtry, MESSAGEMAIN_spamtry2, 0);
+					PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					if(passw) free(passw);
+					goto End_part;
+				}
+
+				// do not allow posts to old threads
+				if ( ROOT > 0 && ((DB.VIndexCountInDB() - ROOT) > MAX_DELTA_POST_MESSAGE) ) {
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP, ROOT);
+					PrintBoardError(MESSAGEMAIN_add_closed, MESSAGEMAIN_add_closed2, 0);
+					PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					if(passw) free(passw);
+					goto End_part;
+
+				}
+			
+				mes.Date = time(NULL);	//	set current time
+				mes.MDate = (time_t)0;	//	haven't modified
+				char *banreason = NULL;
+				if((cr = DB.DB_InsertMessage(&mes, ROOT, strlen(mesb), &mesb, CFlags, passw, &banreason)) != MSG_CHK_ERROR_PASSED)
+				{
+					char *c_ActionResult1, *c_ActionResult2;
+					PrepareActionResult(cr, &c_ActionResult1, &c_ActionResult2);
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP, ROOT);
+					PrintBoardError(c_ActionResult1, c_ActionResult2, 0);
+
+					if(cr == MSG_CHK_ERROR_BANNED && banreason) {
+						// print the reason if it exists
+						printf(DESIGN_BAN_REASON_STYLE, MESSAGEMAIN_BANNED_REASON, banreason);
+					}
+					if(banreason) free(banreason);
+				}
+				else {
+					//	Mark that IP as already posted
+					CheckPostfromIPValidity(Nip, POST_TIME_LIMIT);
+
+					//	posted, set new cookie
+					cookie_name = (char*)realloc(cookie_name, AUTHOR_NAME_LENGTH);
+					strcpy(cookie_name, mes.AuthorName);
+
+
+					//
+					//	Log in user if requested
+					//
+					if(LogMeIn && (passw != NULL && *passw != 0)) {
+						LogMeIn = 0;
+						/* if session already opened - close it */
+						if(ULogin.LU.ID[0] != 0)
+							ULogin.CloseSession(ULogin.LU.ID);
+
+						if(ULogin.OpenSession(mes.AuthorName, passw, NULL, Nip, 0) == 1) {
+							// entered, ok
+							LogMeIn = 1;
+						}
+					}
+					else LogMeIn = 0;
+
+					//
+					//	Check if message was posted to rolled thread than we should change ROOT to main root of thread
+					//
+					DWORD tmpxx;
+					if((mes.Flag & MESSAGE_COLLAPSED_THREAD)) {
+						SMessage parmes;
+						if(!ReadDBMessage(mes.ParentThread, &parmes)) printhtmlerror();
+						tmpxx = parmes.ViIndex;
+					}
+					else tmpxx = mes.ViIndex;
+
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP,
+						tmpxx, ROOT);
+					if(LogMeIn) {
+						// if we have logged in also
+						PrintBoardError(MESSAGEMAIN_add_ok_login, MESSAGEMAIN_add_ok2, HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_THREAD, mes.ViIndex);
+					}
+					else PrintBoardError(MESSAGEMAIN_add_ok, MESSAGEMAIN_add_ok2, HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_THREAD, mes.ViIndex);
+
+					PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP, tmpxx, ROOT);
+
+					if(passw != NULL) free(passw);
+
+					goto End_part;
+				}
+			}
+			break;
+		case ACTION_PREVIEW:
+			{
+				//**********************************************
+				//	preview message
+				//**********************************************
+				DWORD rf;
+				SProfile_UserInfo UI;
+
+				//
+				//	set some fields of message
+				//
+				mes.ParentThread = NO_MESSAGE_CODE;
+				mes.Date = time(NULL);
+				mes.MDate = 0;
+				mes.ViIndex = 0;
+
+				if(ULogin.LU.ID[0] != 0) {
+					memcpy(&UI, ULogin.pui, sizeof(UI));
+					strcpy(mes.AuthorName, UI.username);
+				}
+				else {
+					/* default user */
+					UI.secur = DEFAULT_NOBODY_SECURITY_BYTE;
+					UI.right = DEFAULT_NOBODY_RIGHT;
+					UI.secheader = DEFAULT_NOBODY_HDR_SEC_BYTE;
+					UI.UniqID = 0;
+					UI.username[0] = 0;
+				}
+
+				if(UI.right & USERRIGTH_ALLOW_HTML) CFlags = CFlags | MSG_CHK_ALLOW_HTML;
+				mes.Security = UI.secur;
+				mes.SecHeader = UI.secheader;
+				mes.UniqUserID = UI.UniqID;
+
+				char *banreason = NULL;
+				if((cr = CheckSpellingBan(&mes, &mesb, &banreason, CFlags, &rf)) != MSG_CHK_ERROR_PASSED)
+				{
+					char *c_ActionResult1, *c_ActionResult2;
+					PrepareActionResult(cr, &c_ActionResult1, &c_ActionResult2);
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP, ROOT);
+					PrintBoardError(c_ActionResult1, c_ActionResult2, 0);
+
+					if(cr == MSG_CHK_ERROR_BANNED && banreason) {
+						// print the reason if it exists
+						printf(DESIGN_BAN_REASON_STYLE, MESSAGEMAIN_BANNED_REASON, banreason);
+					}
+				}
+				if(banreason) free(banreason);
+
+				mes.Flag = rf;
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+				printf(DESIGN_PREVIEW_PREVIEWMESSAGE, MESSAGEHEAD_preview_preview_message);
+
+				// fix message body size for print preview
+				mes.msize = 1;	// any constant greater than zero
+
+				DB.PrintHtmlMessageBody(&mes, mesb);
+
+				printf(DESIGN_PREVIEW_CHANGEMESSAGE, MESSAGEHEAD_preview_change_message);
+
+				PrintMessageForm(&mes, mesb, ROOT, ACTION_BUTTON_POST | ACTION_BUTTON_PREVIEW, CFlags);
+				free(mesb);
+			}
+			break;
+		case ACTION_EDIT:
+			{
+				SMessage msg;
+				SProfile_UserInfo UI;
+				free(st);
+
+				//
+				//	Read the message cause we'll need some parts of it
+				//
+				if(!ReadDBMessage(DB.TranslateMsgIndex(ROOT), &msg)) printhtmlerror();
+
+				// we should leave current time intact and modify only modified
+				msg.MDate = time(NULL);		// have been modified
+
+				strcpy(msg.MessageHeader, mes.MessageHeader);
+				strcpy(msg.AuthorName, mes.AuthorName);
+				strcpy(msg.HostName, mes.HostName);
+				if((ULogin.pui->right & USERRIGHT_SUPERUSER) && c_host && c_host[0] != 0) {
+					strcpy(msg.HostName, c_host);
+					msg.HostName[HOST_NAME_LENGTH - 1] = 0;
+				}
+				msg.IPAddr = Nip;
+
+				// Check security rights
+				if(ULogin.LU.ID[0] == 0 || (
+					!(ULogin.pui->right & USERRIGHT_SUPERUSER) &&
+					(ULogin.pui->UniqID != msg.UniqUserID)
+					)
+				) {
+					if(passw) free(passw);
+					printaccessdenied(deal);
+					goto End_part;
+				}
+				if((ULogin.pui->right & USERRIGHT_SUPERUSER))
+				{
+					CProfiles *uprof = new CProfiles();
+					if(uprof->errnum != PROFILE_RETURN_ALLOK) {
+#if ENABLE_LOG >= 1
+						print2log("Error working with profiles database (init)");
+#endif
+						printhtmlerror();
+					}
+					// if user does not exist - it should be unreg
+					if(uprof->GetUserByName(mes.AuthorName, &UI, NULL, NULL) != PROFILE_RETURN_ALLOK)
+						msg.UniqUserID = 0;
+					delete uprof;
+				}
+				else {
+					strcpy(msg.AuthorName, ULogin.pui->username);
+				}
+
+				char *banreason;
+				if((cr = DB.DB_ChangeMessage(ROOT, &msg, // what message
+					&mesb, strlen(mesb), CFlags, &banreason)) != MSG_CHK_ERROR_PASSED)
+				{
+					char *c_ActionResult1, *c_ActionResult2;
+					PrepareActionResult(cr, &c_ActionResult1, &c_ActionResult2);
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP, ROOT);
+					PrintBoardError(c_ActionResult1, c_ActionResult2, 0);
+
+					if(cr == MSG_CHK_ERROR_BANNED && banreason) {
+						// print the reason if it exists
+						printf(DESIGN_BAN_REASON_STYLE, MESSAGEMAIN_BANNED_REASON, banreason);
+					}
+				}
+				else {
+					//	posted, set new cookie
+					cookie_name = (char*)realloc(cookie_name, AUTHOR_NAME_LENGTH);
+					strcpy(cookie_name, mes.AuthorName);
+					
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP,
+						ROOT);
+					PrintBoardError(MESSAGEMAIN_add_ok, MESSAGEMAIN_add_ok2, HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+				}
+			}
+			break;
+		default:
+			{
+#if ENABLE_LOG > 1
+				print2log("Unknown parameter during message post, st = %s", st);
+#endif
+				if(st) free(st);
+				if(passw) free(passw);
+				goto End_URLerror;
+			}
+		}// switch(action)
+		if(passw) free(passw);
+
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP, ROOT);
+		goto End_part;
+	}
+
+	
+	if(strncmp(deal, "configure", 9) == 0) {
+		st = NULL;
+		if((st = strget(deal,"configure=", 16, '&')) != NULL) {
+			if(strcmp(st, "action") == 0) {
+				free(st);
+				// get parameters
+				par = GetParams(MAX_PARAMETERS_STRING);
+
+				currentss = CONFIGURE_SETTING_DEFAULT_ss;
+				currenttt = CONFIGURE_SETTING_DEFAULT_tt;
+				currenttv = CONFIGURE_SETTING_DEFAULT_tv;
+				currenttc = CONFIGURE_SETTING_DEFAULT_tc;
+				currentlsel = CONFIGURE_SETTING_DEFAULT_lsel;
+				currentdsm = CONFIGURE_SETTING_DEFAULT_dsm;
+				currenttz = DATETIME_DEFAULT_TIMEZONE;
+				
+				if(par != NULL) {
+					char *st, *ss;
+					DWORD tmp;
+
+#define READ_PARAM_MASK(param, var, mask) {		\
+	char *ss = strget(par, param, 20, '&');	\
+	if(ss != NULL) {						\
+		if(strcmp(ss, "1") == 0) {			\
+			var |= mask;					\
+		}									\
+		else {								\
+			var &= (~mask);					\
+		}									\
+		free(ss);							\
+	}										\
+	else var &= (~mask);					\
+}
+
+					// read disable smiles
+					READ_PARAM_MASK("dsm=", currentdsm, 0x01);
+					// read dup (disable upper picture)
+					READ_PARAM_MASK("dup=", currentdsm, 0x02);
+					// read dul (disable second link bar)
+					READ_PARAM_MASK("dul=", currentdsm, 0x04);
+					// read onh (disable own nick highlighing)
+					READ_PARAM_MASK("onh=", currentdsm, 0x08);
+					// read plu (enable + acting like an href)
+					READ_PARAM_MASK("plu=", currentdsm, 0x10);
+					// read host (disable host displaying)
+					READ_PARAM_MASK("host=", currentdsm, 0x20);
+					// read alt nick displaying
+					READ_PARAM_MASK("nalt=", currentdsm, 0x40);
+					// read signature disable
+					READ_PARAM_MASK("dsig=", currentdsm, 0x80);
+					// read show reply form
+					READ_PARAM_MASK("shrp=", currentdsm, 0x100);
+
+#define READ_PARAM_NUM(param, var, vardefault) {\
+	char *ss = strget(par, param, 20, '&');		\
+	if(ss != NULL) {							\
+		DWORD tmp = strtol(ss, &st, 10);		\
+		if(((!(*ss != '\0' && *st == '\0'))		\
+			|| errno == ERANGE)) {				\
+			var = vardefault;					\
+		}										\
+		else {									\
+			var = tmp;							\
+		}										\
+		free(ss);								\
+	}											\
+	else var = vardefault;						\
+}
+
+					// read lsel (show type selection)
+					READ_PARAM_NUM("lsel=", currentlsel, CONFIGURE_SETTING_DEFAULT_lsel);
+					if(currentlsel != 1 && currentlsel != 2)
+						currentlsel = CONFIGURE_SETTING_DEFAULT_lsel;
+					// read tc (time count)
+					READ_PARAM_NUM("tc=", currenttc, CONFIGURE_SETTING_DEFAULT_tc);
+					if(currenttc <= 0)
+						currenttc = CONFIGURE_SETTING_DEFAULT_tc;
+					// read tv (thread value)
+					READ_PARAM_NUM("tv=", currenttv, CONFIGURE_SETTING_DEFAULT_tv);
+					if(currenttv <= 0)
+						currenttv = CONFIGURE_SETTING_DEFAULT_tv;
+					// read tt (read time type)
+					READ_PARAM_NUM("tt=", currenttt, CONFIGURE_SETTING_DEFAULT_tt);
+					if(currenttt < 1 || currenttt > 4)
+						currenttt = CONFIGURE_SETTING_DEFAULT_tt;
+					// read ss (read time type)
+					READ_PARAM_NUM("ss=", currentss, CONFIGURE_SETTING_DEFAULT_ss);
+					if(currentss < 1 || currentss > 4)
+						currentss = CONFIGURE_SETTING_DEFAULT_ss;
+					READ_PARAM_NUM("tz=", currenttz, DATETIME_DEFAULT_TIMEZONE);
+					if(currenttz < -12 || currenttz > 12)
+						currenttz = DATETIME_DEFAULT_TIMEZONE;
+
+#if	TOPICS_SYSTEM_SUPPORT
+					// read topics that should be displayed
+					{
+						currenttopics = 0;
+						DWORD i;
+						for(i = 0; i < TOPICS_COUNT; i++)
+						{
+							char st[30];
+							sprintf(st, "topic%d=", i);
+							if((ss = strget(par, st,  3, '&')) != NULL)
+							{
+								if(strcmp(ss, "on") == 0)
+								{
+									currenttopics |= (1<<i);
+								}
+								free(ss);
+							}
+						}
+					}
+#endif
+
+					//
+					// saving values - profile or cookie way
+					//
+
+					if((ULogin.LU.ID[0] != 0) && (ULogin.pui->Flags & PROFILES_FLAG_VIEW_SETTINGS) ){
+							
+						ULogin.pui->vs.dsm = currentdsm;
+						ULogin.pui->vs.topics = currenttopics;
+						ULogin.pui->vs.tv = currenttv;
+						ULogin.pui->vs.tc = currenttc;
+						ULogin.pui->vs.ss = currentss;
+						ULogin.pui->vs.lsel = currentlsel;
+						ULogin.pui->vs.tt = currenttt;
+						ULogin.pui->vs.tz = currenttz;
+				
+						CProfiles *uprof;
+						uprof = new CProfiles();
+						uprof->ModifyUser(ULogin.pui, NULL, NULL);
+						delete uprof;
+					}
+					else{
+						// settings are not in profile. so new values should be in cookies
+						cookie_lsel = currentlsel;
+						cookie_tc = currenttc;
+						cookie_tt = currenttt;
+						cookie_tv = currenttv;
+						cookie_ss = currentss;
+						cookie_dsm = currentdsm;
+						cookie_topics = currenttopics;
+						cookie_tz = currenttz;
+					 }
+					
+				}
+				free(par);
+				
+				
+				//
+				// Redirect user to the index page
+				//
+				PrintHTMLHeader(HEADERSTRING_REDIRECT_NOW | HEADERSTRING_NO_CACHE_THIS, MAINPAGE_INDEX);
+
+				goto End_part;
+			}
+			free(st);
+
+			Tittle_cat(TITLE_Configure);
+
+			/* print configuration form */
+			PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+			PrintConfig();
+			PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+			/****************************/
+		}
+		goto End_part;
+	}
+
+	if(strncmp(deal, "login", 5) == 0) {
+		st = NULL;
+		if((st = strget(deal,"login=", 16, '&')) != NULL) {
+			
+			if(strcmp(st, "action") == 0) {
+				free(st);
+				// check for User name and password
+				// get parameters
+				par = GetParams(MAX_PARAMETERS_STRING);
+
+				/***************************************/
+				int disableipcheck = 0;
+				char *ipchk;
+				if((ipchk = strget(par, "ipoff=", 10, '&')) != NULL) {
+					if(strcmp(ipchk, "1") == 0) {
+						disableipcheck = 1;
+					}
+					free(ipchk);
+				}
+				st = strget(par,"mname=", PROFILES_MAX_USERNAME_LENGTH - 1, '&');
+				if(st != NULL) {
+					char *ss;
+					ss = strget(par,"mpswd=", PROFILES_MAX_PASSWORD_LENGTH - 1, '&');
+					if(ss != NULL) {
+						/* if session already opened - close it */
+						if(ULogin.LU.ID[0] != 0)
+							ULogin.CloseSession(ULogin.LU.ID);
+
+						if(ULogin.OpenSession(st, ss, NULL, Nip, disableipcheck) == 1) {
+							print2log("User '%s' was logged in (%s)", ULogin.pui->username, getenv(REMOTE_ADDR));
+
+							//	Prepare conference login greetings
+							char boardgreet[1000];
+							char *greetnames[4] = {
+								MESSAGEMAIN_login_helloday,
+								MESSAGEMAIN_login_helloevn,
+								MESSAGEMAIN_login_hellonight,
+								MESSAGEMAIN_login_hellomor
+							};
+							int cur = 2;
+							time_t tt = time(NULL);
+							tm *x = localtime(&tt);
+							if(x->tm_hour >= 6 && x->tm_hour < 10) cur = 3;
+							if(x->tm_hour >= 10 && x->tm_hour < 18) cur = 0;
+							if(x->tm_hour >= 18 && x->tm_hour < 22) cur = 1;
+							sprintf(boardgreet, MESSAGEMAIN_login_ok, greetnames[cur], ULogin.pui->username);
+
+
+							Tittle_cat(TITLE_Login);
+
+							// entered, set new cookie
+							cookie_name = (char*)realloc(cookie_name, AUTHOR_NAME_LENGTH);
+							strcpy(cookie_name, st);
+
+
+							PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_LOGIN | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+							PrintBoardError(boardgreet, MESSAGEMAIN_login_ok2, HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+							PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_LOGIN | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+							free(ss);
+							free(st);
+							goto End_part;
+						}
+						free(ss);
+					}
+					free(st);
+				}
+
+				printpassworderror(deal);
+				goto End_part;
+			}
+
+			if(strcmp(st, "lostpasswform") == 0) {
+				free(st);
+
+				Tittle_cat(TITLE_LostPassword);
+
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_LOGIN, MAINPAGE_INDEX);
+				printf(DESIGN_LOSTPASSW_HEADER, MESSAGEMAIN_lostpassw_header);
+				PrintLostPasswordForm();
+				PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_LOGIN, MAINPAGE_INDEX);
+
+				goto End_part;
+			}
+
+			if(strcmp(st, "lostpasswaction") == 0) {
+				free(st);
+
+				// check for User name and email address
+				// get parameters
+				par = GetParams(MAX_PARAMETERS_STRING);
+
+				/***************************************/
+				st = strget(par,"mname=", PROFILES_MAX_USERNAME_LENGTH - 1, '&');
+				if(st != NULL) {
+					char *ss;
+					ss = strget(par,"memail=", PROFILES_FULL_USERINFO_MAX_EMAIL - 1, '&');
+					if(ss != NULL) {
+						CProfiles uprof;
+						SProfile_FullUserInfo Fui;
+						SProfile_UserInfo ui;
+						if(uprof.GetUserByName(st, &ui, &Fui, NULL) == PROFILE_RETURN_ALLOK) {
+							if(strcmp(Fui.Email, ss) == 0) {
+								//
+								//	We should send password to the user
+								//
+
+								Tittle_cat(TITLE_PasswordSent);
+
+								//
+								//	Send email
+								//
+								{
+									char subj[1000], bdy[10000];
+																		
+									sprintf(subj, MAILACKN_LOSTPASS_SUBJECT, st);
+									
+									sprintf(bdy, MAILACKN_LOSTPASS_BODY, st, ui.password);
+									//print2log("will send message now %s", bdy);
+									wcSendMail(Fui.Email, subj, bdy);
+									
+									print2log("Password was sent to %s", Fui.Email);
+								}
+
+								PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+								PrintBoardError(MESSAGEMAIN_lostpassw_ok, MESSAGEMAIN_lostpassw_ok2, HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+								PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+								free(ss);
+								free(st);
+								goto End_part;
+							}
+						}
+					}
+				}
+
+				Tittle_cat(TITLE_LostPassword);
+
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_LOGIN, MAINPAGE_INDEX);
+				printf(DESIGN_LOSTPASSW_HEADER, MESSAGEMAIN_lostpassw_hretry);
+				PrintLostPasswordForm();
+				PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_LOGIN, MAINPAGE_INDEX);
+
+				goto End_part;
+			}
+
+			if(strcmp(st, "logoff") == 0) {
+				free(st);
+
+				if(ULogin.LU.ID[0] == 0) {
+					/* not logged yet */
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					PrintBoardError(MESSAGEMAIN_logoff_not_logged_in, MESSAGEMAIN_logoff_not_logged_in2, 0);
+					PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					goto End_part;
+				}
+
+				print2log("User '%s' was logged out (%s)", ULogin.pui->username, getenv(REMOTE_ADDR));
+
+				/* close sequence */
+				ULogin.CloseSession(ULogin.LU.ID);
+				
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+				
+				PrintBoardError(MESSAGEMAIN_logoff_ok, MESSAGEMAIN_logoff_ok, HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+				
+				PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+				goto End_part;
+			}
+			free(st);
+		}
+
+		Tittle_cat(TITLE_Login);
+
+		/******* print login form *******/
+		PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_LOGIN, MAINPAGE_INDEX);
+		printf(DESIGN_MODERATOR_ENTER_HEADER, MESSAGEMAIN_login_login_header);
+		PrintLoginForm();
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_LOGIN, MAINPAGE_INDEX);
+		/********************************/
+		goto End_part;
+	}
+	
+	if(strncmp(deal, "close", 5) == 0) {
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_CLOSE_MESSAGE) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+
+		if((st = strget(deal,"close=", 16, '&')) != NULL) {
+			char *ss;
+			DWORD midx;
+			errno = 0;
+			DWORD tmp = strtol(st, &ss, 10);
+			if((!(*st != '\0' && *ss == '\0')) || errno == ERANGE ||
+				tmp < 1 || ((midx = DB.TranslateMsgIndex(tmp)) == NO_MESSAGE_CODE) ) {
+				printnomessage(deal);
+			}
+			else {
+				/* Security check for own message or USERRIGHT_SUPERUSER */
+
+				/******** read message ********/
+				if(!ReadDBMessage(midx, &mes)) printhtmlerror();
+				/* closing by author allowed in main thread only ! */
+				if(ULogin.LU.ID[0] != 0 && ((mes.UniqUserID == ULogin.LU.UniqID && mes.Level == 0) || (ULogin.LU.right & USERRIGHT_SUPERUSER))) {
+
+					Tittle_cat(TITLE_ClosingMessage);
+
+					DB.DB_ChangeCloseThread(tmp, 1);
+					print2log("Message %d (%s (by %s)) was closed by %s", tmp, mes.MessageHeader, mes.AuthorName, ULogin.pui->username);
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP,
+						tmp);
+					PrintBoardError(MESSAGEMAIN_threadwasclosed, MESSAGEMAIN_threadwasclosed2,
+						HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+					PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP,
+						tmp);
+				}
+				else printaccessdenied(deal);
+			}
+			free(st);
+		}
+		else goto End_URLerror;
+		goto End_part;
+	}
+	
+	
+	if(strncmp(deal, "hide", 4) == 0) {
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+
+		if((st = strget(deal,"hide=", 16, '&')) != NULL) {
+			errno = 0;
+			char *ss;
+			DWORD tmp = strtol(st, &ss, 10);
+			if((!(*st != '\0' && *ss == '\0')) || errno == ERANGE ||
+				tmp < 1 || DB.TranslateMsgIndex(tmp) == NO_MESSAGE_CODE) {
+				printnomessage(deal);
+			}
+			else {
+				DB.DB_ChangeInvisibilityThreadFlag(tmp, 1);
+				if(!ReadDBMessage(DB.TranslateMsgIndex(tmp), &mes)) printhtmlerror();
+				print2log("Message %d (%s (by %s)) was hided by %s", tmp, mes.MessageHeader, mes.AuthorName, ULogin.pui->username);
+
+				Tittle_cat(TITLE_HidingMessage);
+
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP,
+					tmp);
+				PrintBoardError(MESSAGEMAIN_threadchangehided, MESSAGEMAIN_threadchangehided2,
+					HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+				PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP,
+					tmp);
+			}
+			free(st);
+		}
+		else goto End_URLerror;
+		goto End_part;
+	}
+	
+	
+	if(strncmp(deal, "unhide", 6) == 0) {
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+
+		if((st = strget(deal,"unhide=", 16, '&')) != NULL) {
+			errno = 0;
+			char *ss;
+			DWORD tmp = strtol(st, &ss, 10);
+			if((!(*st != '\0' && *ss == '\0')) || errno == ERANGE ||
+				tmp < 1 || DB.TranslateMsgIndex(tmp) == NO_MESSAGE_CODE) {
+				printnomessage(deal);
+			}
+			else {
+				Tittle_cat(TITLE_HidingMessage);
+
+				DB.DB_ChangeInvisibilityThreadFlag(tmp, 0);
+				if(!ReadDBMessage(DB.TranslateMsgIndex(tmp), &mes)) printhtmlerror();
+				print2log("Message %d (%s (by %s)) was unhided by %s", tmp, mes.MessageHeader, mes.AuthorName, ULogin.pui->username);
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP,
+					tmp);
+				PrintBoardError(MESSAGEMAIN_threadchangehided, MESSAGEMAIN_threadchangehided2,
+					HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+				PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP,
+					tmp);
+			}
+			free(st);
+		}
+		else goto End_URLerror;
+		goto End_part;
+	}
+	
+	if(strncmp(deal, "unclose", 7) == 0) {
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_OPEN_MESSAGE) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+
+		if((st = strget(deal,"unclose=", 16, '&')) != NULL) {
+			char *ss;
+			DWORD midx;
+			errno = 0;
+			DWORD tmp = strtol(st, &ss, 10);
+			if((!(*st != '\0' && *ss == '\0')) || errno == ERANGE ||
+				tmp < 1 || ((midx = DB.TranslateMsgIndex(tmp)) == NO_MESSAGE_CODE) ) {
+				printnomessage(deal);
+			}
+			else {
+				/* Security check for own message or USERRIGHT_SUPERUSER */
+
+				/******** read message ********/
+				if(!ReadDBMessage(midx, &mes)) printhtmlerror();
+				if(ULogin.LU.ID[0] != 0 && (mes.UniqUserID == ULogin.LU.UniqID || (ULogin.LU.right & USERRIGHT_SUPERUSER))) {
+
+					Tittle_cat(TITLE_ClosingMessage);
+
+					DB.DB_ChangeCloseThread(tmp, 0);
+					if(!ReadDBMessage(DB.TranslateMsgIndex(tmp), &mes)) printhtmlerror();
+					print2log("Message %d (%s (by %s)) was opened by %s", tmp, mes.MessageHeader, mes.AuthorName, ULogin.pui->username);
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP,
+						tmp);
+					PrintBoardError(MESSAGEMAIN_threadwasclosed, MESSAGEMAIN_threadwasclosed2,
+						HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+					PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE |
+						HEADERSTRING_DISABLE_FAQHELP, tmp);
+				}
+				else printaccessdenied(deal);
+			}
+			free(st);
+		}
+		else goto End_URLerror;
+		goto End_part;
+	}
+
+	if(strncmp(deal, "roll", 4) == 0) {
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+
+		if((st = strget(deal,"roll=", 16, '&')) != NULL) {
+			errno = 0;
+			char *ss;
+			DWORD tmp = strtol(st, &ss, 10);
+			if((!(*st != '\0' && *ss == '\0')) || errno == ERANGE ||
+				tmp < 1 || DB.TranslateMsgIndex(tmp) == NO_MESSAGE_CODE) {
+				printnomessage(deal);
+			}
+			else {
+
+				Tittle_cat(TITLE_RollMessage);
+
+				DB.DB_ChangeRollThreadFlag(tmp);
+				if(!ReadDBMessage(DB.TranslateMsgIndex(tmp), &mes)) printhtmlerror();
+				print2log("Message %d (%s (by %s)) was (un)rolled by %s", tmp, mes.MessageHeader, mes.AuthorName, ULogin.pui->username);
+
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE,
+					tmp);
+				PrintBoardError(MESSAGEMAIN_threadrolled, MESSAGEMAIN_threadrolled2,
+					HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+				PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE,
+					tmp);
+			}
+			free(st);
+		}
+		else goto End_URLerror;
+		goto End_part;
+	}
+	
+	if(strncmp(deal, "delmsg", 6) == 0) {
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+
+		if((st = strget(deal,"delmsg=", 16, '&')) != NULL) {
+			errno = 0;
+			char *ss;
+			DWORD tmp = strtol(st, &ss, 10);
+			
+			if((!(*st != '\0' && *ss == '\0')) || errno == ERANGE ||
+				tmp < 1 || DB.TranslateMsgIndex(tmp) == NO_MESSAGE_CODE) {
+				printnomessage(deal);
+			}
+			else {
+
+				Tittle_cat(TITLE_DeletingMessage);
+
+				if(!ReadDBMessage(DB.TranslateMsgIndex(tmp), &mes)) printhtmlerror();
+				print2log("Message %d (%s (by %s)) was deleted by %s", tmp, mes.MessageHeader, mes.AuthorName, ULogin.pui->username);
+				DB.DB_DeleteMessages(tmp);
+				
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP, tmp);
+				PrintBoardError(MESSAGEMAIN_threaddeleted, MESSAGEMAIN_threaddeleted2,
+					HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+				PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP,
+					tmp);
+			}
+			free(st);
+		}
+		else goto End_URLerror;
+		goto End_part;
+	}
+	
+	if(strncmp(deal, "changemsg", 9) == 0) {
+		// precheck security
+		if((ULogin.LU.right & USERRIGHT_MODIFY_MESSAGE) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+
+		if((st = strget(deal,"changemsg=", 16, '&')) != NULL) {
+			errno = 0;
+			char *ss;
+			DWORD tmp = strtol(st, &ss, 10);
+			DWORD midx;
+			if( (!(*st != '\0' && *ss == '\0')) || errno == ERANGE ||
+				tmp < 1 || ((midx = DB.TranslateMsgIndex(tmp)) == NO_MESSAGE_CODE)) {
+				printnomessage(deal);
+			}
+			else {
+				//
+				//	read message
+				//
+				if(!ReadDBMessage(midx, &mes)) printhtmlerror();
+
+				//
+				//	security check
+				//
+				if(!( (ULogin.LU.right & USERRIGHT_SUPERUSER) || (	// admin ?
+						((mes.Flag & MESSAGE_IS_INVISIBLE) == 0) && // not hided
+						((mes.Flag & MESSAGE_IS_CLOSED) == 0) &&	// and not closed
+						(ULogin.LU.right & USERRIGHT_MODIFY_MESSAGE) &&	// can modify?
+						(mes.UniqUserID == ULogin.LU.UniqID) )	// message posted by this user
+					))
+				{
+					Tittle_cat(TITLE_Error);
+					printaccessdenied(deal);
+				}
+				else {
+#if STABLE_TITLE == 0
+					// set title - change title to change message
+					ConfTitle = (char*)realloc(ConfTitle, strlen(ConfTitle) + strlen(TITLE_divider) + strlen(TITLE_ChangingMessage) + strlen(mes.MessageHeader) + 6);
+					strcat(ConfTitle, TITLE_divider);
+					strcat(ConfTitle, TITLE_ChangingMessage);
+					strcat(ConfTitle, " - ");
+					strcat(ConfTitle, mes.MessageHeader);
+#endif
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, tmp);
+
+					PrintMessageThread(&DB, tmp, mes.Flag, mes.UniqUserID);
+
+					char *mesb = (char*)malloc(mes.msize + 1);
+					mesb[0] = 0;
+
+					//
+					//	Read message body
+					//
+					if(!ReadDBMessageBody(mesb, mes.MIndex, mes.msize))
+						printhtmlerrorat(LOG_UNABLETOLOCATEFILE, F_MSGBODY);
+
+					PrintMessageForm(&mes, mesb, tmp, ACTION_BUTTON_EDIT);
+
+					free(mesb);
+
+					PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, tmp);
+				}
+			}
+			free(st);
+		}
+		else goto End_URLerror;
+		goto End_part;
+	}
+	
+	if(strncmp(deal, "help", 4) == 0) {
+
+		Tittle_cat(TITLE_HelpPage);
+
+		PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP, MAINPAGE_INDEX);
+		
+		PrintFAQForm();
+		
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP, MAINPAGE_INDEX);
+		goto End_part;
+	}
+
+	if(strncmp(deal, "uinfo", 5) == 0) {
+		char *name;
+		if((name = strget(deal,"uinfo=", PROFILES_MAX_USERNAME_LENGTH, '&')) != NULL) {
+#if STABLE_TITLE == 0
+			ConfTitle = (char*)realloc(ConfTitle, strlen(ConfTitle) + 2*strlen(TITLE_divider) + strlen(TITLE_ProfileInfo) + strlen(name) + 1);
+			strcat(ConfTitle, TITLE_divider);
+			strcat(ConfTitle, TITLE_ProfileInfo);
+			strcat(ConfTitle, TITLE_divider);
+			strcat(ConfTitle, name);
+#endif
+			PrintHTMLHeader(HEADERSTRING_DISABLE_ALL, 0);
+			
+			PrintAboutUserInfo(name);
+			
+			PrintBottomLines(HEADERSTRING_DISABLE_ALL, 0);
+			free(name);
+		}
+		else goto End_URLerror;
+		goto End_part;
+	}
+
+	if(strncmp(deal, "searchword", 10) == 0) {
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_VIEW_MESSAGE) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+
+		char *ss;
+		DWORD start = 0;
+		if((ss = strget(deal,"searchword=", 255 - 1, '&')) != NULL) {
+			if((st = strget(deal,"start=", 60, '&')) != NULL) {
+				errno = 0;
+				char *ss;
+				start = strtol(st, &ss, 10);
+				if( (!(*st != '\0' && *ss == '\0')) || errno == ERANGE || tmp == 0) {
+					start = 1;
+				}
+				free(st);
+			}
+			else start = 1;
+
+			if(strlen(ss) > 0) {
+				Tittle_cat(TITLE_Search);
+
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_SEARCH, MAINPAGE_INDEX | HEADERSTRING_NO_CACHE_THIS);
+				PrintSearchForm(ss, &DB);
+				if(strlen(ss) >= SEARCHER_MIN_WORD) {
+					CMessageSearcher *ms = new CMessageSearcher(SEARCHER_INDEX_CREATE_EXISTING);
+					if(ms->errnum == SEARCHER_RETURN_ALLOK) {
+						DWORD c;
+						DWORD *vmsg = ms->SearchMessagesByPattern(ss, &c);
+						printf(DESIGN_SEARCH_SEARCH_STR_WAS, MESSAGEMAIN_search_search_str, ms->srch_str);
+						if(c != 0) {
+							// print count of found messages
+							printf(DESIGN_SEARCH_RESULT, MESSAGEMAIN_search_result1, c, MESSAGEMAIN_search_result2);
+						}
+						else {
+							// Nothing have been found
+							printf(DESIGN_SEARCH_NO_RESULT, MESSAGEMAIN_search_result1, MESSAGEMAIN_search_result_nothing);
+						}
+
+						//	Check and adjust start
+						if(c <= (start-1)*SEARCH_MES_PER_PAGE_COUNT) {
+							start = c/SEARCH_MES_PER_PAGE_COUNT + 1;
+						}
+
+						DWORD oldc = c;
+						if(c > SEARCH_MES_PER_PAGE_COUNT) {
+							char *wrd = CodeHttpString(ss, 0);
+							if(wrd) {
+								printf("<CENTER>" MESSAGEMAIN_search_result_pages);
+								int max = (c/SEARCH_MES_PER_PAGE_COUNT) + 
+									(((c % SEARCH_MES_PER_PAGE_COUNT) == 0)? 0: 1);
+								for(int i = 0; i < max; i++) {
+									if(i > 0 && (i % 20) == 0) printf("<BR>");
+									if(i != start - 1) printf("&nbsp;<A HREF=\"?searchword=%s&start=%d\">%d</A>&nbsp;", wrd, i+1, i+1);
+									else printf("<BOLD>&nbsp;%d&nbsp;</BOLD>", i+1);
+								}
+								printf("</CENTER>");
+							}
+						}
+
+						if(c - (start-1)*SEARCH_MES_PER_PAGE_COUNT > SEARCH_MES_PER_PAGE_COUNT) c = SEARCH_MES_PER_PAGE_COUNT;
+						else c = c - (start-1)*SEARCH_MES_PER_PAGE_COUNT;
+						DB.PrintHtmlMessageBufferByVI(vmsg + (start-1)*SEARCH_MES_PER_PAGE_COUNT, c);
+						free(vmsg);
+
+						c = oldc;
+						if(c > SEARCH_MES_PER_PAGE_COUNT) {
+							char *wrd = CodeHttpString(ss, 0);
+							if(wrd) {
+								printf("<BR><CENTER>" MESSAGEMAIN_search_result_pages);
+								int max = (c/SEARCH_MES_PER_PAGE_COUNT) + 
+									(((c % SEARCH_MES_PER_PAGE_COUNT) == 0)? 0: 1);
+								for(int i = 0; i < max; i++) {
+									if(i > 0 && (i % 20 == 0)) printf("<BR>");
+									if(i != start - 1) printf("&nbsp;<A HREF=\"?searchword=%s&start=%d\">%d</A>&nbsp;", wrd, i+1, i+1);
+									else printf("<BOLD>&nbsp;%d&nbsp;</BOLD>", i+1);
+								}
+								printf("</CENTER>");
+							}
+						}
+					}
+					else {
+						//	Write that searcher have not been configured properly
+					}
+					delete ms;
+				}
+				PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_SEARCH, MAINPAGE_INDEX);
+				free(ss);
+				goto End_part;
+			}
+		}
+
+		Tittle_cat(TITLE_Search);
+
+		PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_SEARCH, MAINPAGE_INDEX);
+		
+		PrintSearchForm("", &DB, 1);
+		
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_SEARCH, MAINPAGE_INDEX);
+
+		goto End_part;
+	}
+
+	if(strncmp(deal, "search", 6) == 0) {
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_VIEW_MESSAGE) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+
+		if((st = strget(deal,"search=", 60, '&')) != NULL) {
+			if(strcmp(st, "action") == 0) {
+				free(st);
+				
+				/* get "method post" parameters */
+				par = GetParams(MAX_PARAMETERS_STRING);
+				if(par != NULL) {
+					char *ss;
+					/* read search pattern */
+					ss = strget(par, "find=", 255 - 1, '&');
+					if(ss == NULL) {
+						ss = (char*)malloc(1);
+						ss[0] = 0;
+					}
+
+					Tittle_cat(TITLE_Search);
+
+#if ENABLE_LOG == 2
+					print2log("Search from %s, query=%s", getenv(REMOTE_ADDR), ss);
+#endif
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_SEARCH, MAINPAGE_INDEX);
+					PrintSearchForm(ss, &DB);
+					if(strlen(ss) >= SEARCHER_MIN_WORD) {
+						CMessageSearcher *ms = new CMessageSearcher(SEARCHER_INDEX_CREATE_EXISTING);
+						if(ms->errnum == SEARCHER_RETURN_ALLOK) {
+							DWORD c;
+							DWORD *vmsg = ms->SearchMessagesByPattern(ss, &c);
+							printf(DESIGN_SEARCH_SEARCH_STR_WAS, MESSAGEMAIN_search_search_str, ms->srch_str);
+							if(c != 0) {
+								// print count of found messages
+								printf(DESIGN_SEARCH_RESULT, MESSAGEMAIN_search_result1, c, MESSAGEMAIN_search_result2);
+							}
+							else {
+								// Nothing have been found
+								printf(DESIGN_SEARCH_NO_RESULT, MESSAGEMAIN_search_result1, MESSAGEMAIN_search_result_nothing);
+							}
+							if(c > SEARCH_MES_PER_PAGE_COUNT) {
+								char *wrd = CodeHttpString(ss, 0);
+								if(wrd) {
+									printf("<CENTER>" MESSAGEMAIN_search_result_pages);
+									int max = (c/SEARCH_MES_PER_PAGE_COUNT) + 
+										(((c % SEARCH_MES_PER_PAGE_COUNT) == 0)? 0: 1);
+									for(int i = 0; i < max; i++) {
+										if(i > 0 && (i % 20 == 0)) printf("<BR>");
+										if(i != 0) printf("&nbsp;<A HREF=\"?searchword=%s&start=%d\">%d</A>&nbsp;", wrd, i+1, i+1);
+										else printf("<BOLD>&nbsp;%d&nbsp;</BOLD>", i+1);
+									}
+									printf("</CENTER>");
+								}
+							}
+							DWORD oldc = c;
+							if(c > 0) {
+								if( c > SEARCH_MES_PER_PAGE_COUNT) c = SEARCH_MES_PER_PAGE_COUNT;
+								DB.PrintHtmlMessageBufferByVI(vmsg, c);
+								free(vmsg);
+							}
+							c = oldc;
+							if(c > SEARCH_MES_PER_PAGE_COUNT) {
+								char *wrd = CodeHttpString(ss, 0);
+								if(wrd) {
+									printf("<BR><CENTER>" MESSAGEMAIN_search_result_pages);
+									int max = (c/SEARCH_MES_PER_PAGE_COUNT) + 
+										(((c % SEARCH_MES_PER_PAGE_COUNT) == 0)? 0: 1);
+									for(int i = 0; i < max; i++) {
+										if(i > 0 && (i % 20 == 0)) printf("<BR>");
+										if(i != 0) printf("&nbsp;<A HREF=\"?searchword=%s&start=%d\">%d</A>&nbsp;", wrd, i+1, i+1);
+										else printf("<BOLD>&nbsp;%d&nbsp;</BOLD>", i+1);
+									}
+									printf("</CENTER>");
+								}
+							}
+						}
+						else {
+							//	Write that searcher have not been configured properly
+						}
+						delete ms;
+					}
+					PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_SEARCH, MAINPAGE_INDEX);
+					free(ss);
+					goto End_part;
+				}
+				else goto End_URLerror;
+			}
+			free(st);
+		}
+
+		Tittle_cat(TITLE_Search);
+
+		PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_SEARCH, MAINPAGE_INDEX);
+		
+		PrintSearchForm("", &DB, 1);
+		
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_SEARCH, MAINPAGE_INDEX);
+
+		goto End_part;
+	}
+
+	if(strncmp(deal, "changeusr=", 8) == 0) {
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+		if((st = strget(deal,"changeusr=", 30, '&')) != NULL) {
+			if(strcmp(st, "action") == 0) {
+				free(st);
+
+				//	here we do it :)
+				//	get parameters
+				par = GetParams(MAX_PARAMETERS_STRING);
+				if(par !=NULL) {
+					BYTE sechdr, secbdy, ustat;
+					DWORD right = 0;
+					char *name;
+
+					/* security byte header */
+					if((st = strget(par, "sechdr=", 10, '&')) != NULL) {
+						errno = 0;
+						char *ss;
+						sechdr = (BYTE)strtol(st, &ss, 10);
+						if( (!(*st != '\0' && *ss == '\0')) || errno == ERANGE) {
+							sechdr = 255;
+						}
+						free(st);
+					}
+					else sechdr = 255;
+
+					/* name */
+					name = strget(par, "name=", PROFILES_MAX_USERNAME_LENGTH - 1, '&');
+
+					/* security byte body */
+					if((st = strget(par, "secbdy=", 10, '&')) != NULL) {
+						errno = 0;
+						char *ss;
+						secbdy = (BYTE)strtol(st, &ss, 10);
+						if( (!(*st != '\0' && *ss == '\0')) || errno == ERANGE) {
+							secbdy = 255;
+						}
+						free(st);
+					}
+					else secbdy = 255;
+
+					/* ustat */
+					if((st = strget(par, "ustat=", 10, '&')) != NULL) {
+						errno = 0;
+						char *ss;
+						ustat = (BYTE)strtol(st, &ss, 10);
+						if( (!(*st != '\0' && *ss == '\0')) || errno == ERANGE || ustat >= USER_STATUS_COUNT) {
+							ustat = 0;
+						}
+						free(st);
+					}
+					else ustat = 0;
+
+					// read the right
+					{
+						DWORD i;
+						char *ss;
+						right = 0;
+						for(i = 0; i < USERRIGHT_COUNT; i++)
+						{
+							char st[30];
+							sprintf(st, "right%d=", i);
+							if((ss = strget(par, st,  4, '&')) != NULL)
+							{
+								if(strcmp(ss, "on") == 0)
+								{
+									right |= (1<<i);
+								}
+								free(ss);
+							}
+						}
+					}
+
+					//
+					//	Update the user
+					//
+					int updated = 0;
+					if(name) {
+						CProfiles *uprof;
+						SProfile_UserInfo ui;
+						SProfile_FullUserInfo fui;
+						DWORD err = 0;
+						DWORD idx;
+
+						uprof = new CProfiles();
+						err = uprof->GetUserByName(name, &ui, &fui, &idx);
+						if(err == PROFILE_RETURN_ALLOK) {
+							int altnupd = 0;
+							// delete alt name if required
+							if(((ui.right & USERRIGHT_SUPERUSER) != 0 ||
+								(ui.right & USERRIGHT_ALT_DISPLAY_NAME) != 0) &&
+							   ((right & USERRIGHT_ALT_DISPLAY_NAME) == 0 &&
+								(right & USERRIGHT_SUPERUSER) == 0)
+							  )
+							{
+								ui.Flags &= (~PROFILES_FLAG_ALT_DISPLAY_NAME);
+								altnupd = 1;
+							}
+
+							ui.secur = secbdy;
+							ui.secheader = sechdr;
+							ui.Status = ustat;
+							ui.right = right;
+
+							if(uprof->SetUInfo(idx, &ui)) {
+								if(altnupd) AltNames.DeleteAltName(ui.UniqID);
+								updated = 1;
+							}
+						}
+						if(uprof) delete uprof;
+					}
+
+					//
+					//	Write complete message
+					//
+					if(updated) {
+						Tittle_cat(TITLE_Registration);
+
+						PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE,
+							MAINPAGE_INDEX);
+						PrintBoardError(MESSAGEMAIN_register_edit_ex, MESSAGEMAIN_register_edit_ex2,
+							HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+						PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE,
+							MAINPAGE_INDEX);
+
+						// log this task
+						print2log("User %s was updated by %s", name, ULogin.pui->username);
+					}
+					else {
+						Tittle_cat(TITLE_Error);
+
+						PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+						PrintBoardError(MESSAGEMAIN_register_edit_err, MESSAGEMAIN_register_edit_err2, 0);
+						PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					}
+
+					free(par);
+					goto End_part;
+				}
+				else goto End_URLerror;
+			}
+			free(st);
+		}
+
+		goto End_URLerror;
+	}
+
+	if(strncmp(deal, "register", 8) == 0) {
+		/* security check */
+		if((ULogin.LU.right & USERRIGTH_PROFILE_CREATE) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+		// We do not need to check security there, this action due to be done lately in DoCheckAndCreateProfile()
+		if((st = strget(deal,"register=", 30, '&')) != NULL) {
+			if(strcmp(st, "action") == 0) {
+				free(st);
+				SProfile_FullUserInfo fui;
+				SProfile_UserInfo ui;
+
+				/****** set default user creation parameters ******/
+				ui.Flags = 0; // don't have picture or signature
+				ui.right = DEFAULT_USER_RIGHT;
+				ui.secur = DEFAULT_USER_SECURITY_BYTE;
+				ui.secheader = DEFAULT_USER_HDR_SEC_BYTE;
+				/**************************************************/
+
+				/* get parameters */
+				par = GetParams(MAX_PARAMETERS_STRING);
+				if(par !=NULL) {
+					char *ss, *passwdconfirm, *oldpasswd, *act, *mb;
+
+					/* what we should do: edit, delete or create */
+					act = strget(par, "register=", 255, '&');
+					if(act == NULL) {
+						// default action - register
+						act = (char*)malloc(100);
+						strcpy(act, MESSAGEMAIN_register_register);
+					}
+
+					/* read login name (username) and load user profile if update */
+					ss = strget(par, "login=", PROFILES_MAX_USERNAME_LENGTH - 1, '&');
+					if(ss != NULL) {
+						strcpy(ui.username, ss);
+						free(ss);
+					}
+					else {
+						if(ULogin.LU.ID[0] != 0)
+							strcpy(ui.username, ULogin.pui->username);
+						else ui.username[0] = 0;
+					}
+					/* if edit - load current settings */
+					if(strcmp(act, MESSAGEMAIN_register_edit) == 0 && ui.username[0] != 0) {
+						CProfiles *cp = new CProfiles();
+						cp->GetUserByName(ui.username, &ui, &fui, NULL);
+						delete cp;
+					}
+
+					//	Read alternative display name for user
+					ss = strget(par, "dispnm=", PROFILES_MAX_ALT_DISPLAY_NAME - 1, '&');
+					if(ss != NULL) {
+						strcpy(ui.altdisplayname, ss);
+						free(ss);
+					}
+					else ui.altdisplayname[0] = 0;
+
+					/* read password 1 */
+					ss = strget(par, "pswd1=", PROFILES_MAX_PASSWORD_LENGTH - 1, '&');
+					if(ss != NULL) {
+						strcpy(ui.password, ss);
+						free(ss);
+					}
+					else ui.password[0] = 0;
+					
+					/* read password 2 */
+					passwdconfirm = strget(par, "pswd2=", PROFILES_MAX_PASSWORD_LENGTH - 1, '&');
+					if(!passwdconfirm)
+					{
+						passwdconfirm = (char*)malloc(2);
+						passwdconfirm[0] = 0;
+					}
+					
+					/* read old password */
+					oldpasswd = strget(par, "opswd=", PROFILES_MAX_PASSWORD_LENGTH - 1, '&');
+					if(!oldpasswd)
+					{
+						oldpasswd = (char*)malloc(2);
+						oldpasswd[0] = 0;
+					}
+
+					/* read full name */
+					ss = strget(par, "name=", PROFILES_FULL_USERINFO_MAX_NAME - 1, '&');
+					if(ss != NULL) {
+						strcpy(fui.FullName, ss);
+						free(ss);
+					}
+					else fui.FullName[0] = 0;
+					
+					/* read email */
+					ss = strget(par, "email=", PROFILES_FULL_USERINFO_MAX_EMAIL - 1, '&');
+					if(ss != NULL) {
+						strcpy(fui.Email, ss);
+						free(ss);
+					}
+					else fui.Email[0] = 0;
+
+					/* read email */
+					ss = strget(par, "icq=", PROFILES_MAX_ICQ_LEN - 1, '&');
+					if(ss != NULL) {
+						strcpy(ui.icqnumber, ss);
+						free(ss);
+					}
+					else ui.icqnumber[0] = 0;
+
+					/* read homepage address */
+					ss = strget(par, "hpage=", PROFILES_FULL_USERINFO_MAX_HOMEPAGE - 1, '&');
+					if(ss != NULL) {
+						strcpy(fui.HomePage, ss);
+						free(ss);
+					}
+					else fui.HomePage[0] = 0;
+					
+					/* read about */
+					fui.AboutUser = strget(par, "about=", MAX_PARAMETERS_STRING - 1, '&');
+
+					// this is needed because of char #10 filtering.
+					// in WIN32 printf() works incorrectly with it
+#if defined(WIN32)
+					FilterMessageForPreview(fui.AboutUser, &mb);
+					strcpy(fui.AboutUser, mb);
+					free(mb);
+#endif
+
+					/* read signature */
+					ss = strget(par, "sign=", PROFILES_MAX_SIGNATURE_LENGTH - 1, '&');
+					if(ss != NULL) {
+						// this is needed because of char #10 filtering.
+						// in WIN32 printf() works incorrectly with it
+#if defined(WIN32)
+						FilterMessageForPreview(ss, &mb);
+						strcpy(fui.Signature, mb);
+						free(mb);
+#else
+						strcpy(fui.Signature, ss);
+#endif
+						free(ss);
+					}
+					else fui.Signature[0] = 0;
+
+					//	read selected users
+					ss = strget(par, "susr=", PROFILES_FULL_USERINFO_MAX_SELECTEDUSR - 1, '&');
+					if(ss != NULL) {
+						// this is needed because of char #10 filtering.
+						// in WIN32 printf() works incorrectly with it
+#if defined(WIN32)
+						FilterMessageForPreview(ss, &mb);
+						strcpy(fui.SelectedUsers, mb);
+						free(mb);
+#else
+						strcpy(fui.SelectedUsers, ss);
+#endif
+						free(ss);
+					}
+					else fui.SelectedUsers[0] = 0;
+
+					/* invisible profile ? */
+					ss = strget(par, "vprf=", 10, '&');
+					if(ss != NULL && strcmp(ss, "1") == 0) {
+						ui.Flags = ui.Flags & (~PROFILES_FLAG_INVISIBLE);
+					}
+					else ui.Flags = ui.Flags | PROFILES_FLAG_INVISIBLE;
+					if(ss != NULL) free(ss);
+
+					/* always email ackn. for every post ? */
+					ss = strget(par, "apem=", 10, '&');
+					if(ss != NULL && strcmp(ss, "1") == 0) {
+						ui.Flags = ui.Flags  | PROFILES_FLAG_ALWAYS_EMAIL_ACKN;
+					}
+					else ui.Flags = ui.Flags & (~PROFILES_FLAG_ALWAYS_EMAIL_ACKN);
+					if(ss != NULL) free(ss);
+
+					/* disabled private messages ? */
+					ss = strget(par, "pdis=", 10, '&');
+					if(ss != NULL && strcmp(ss, "1") == 0) {
+						ui.Flags = ui.Flags | PROFILES_FLAG_PERSMSGDISABLED;
+					}
+					else ui.Flags = ui.Flags & (~PROFILES_FLAG_PERSMSGDISABLED);
+					if(ss != NULL) free(ss);
+
+					/* private message mail ackn ? */
+					ss = strget(par, "peml=", 10, '&');
+					if(ss != NULL && strcmp(ss, "1") == 0) {
+						ui.Flags = ui.Flags | PROFILES_FLAG_PERSMSGTOEMAIL;
+					}
+					else ui.Flags = ui.Flags & (~PROFILES_FLAG_PERSMSGTOEMAIL);
+					if(ss != NULL) free(ss);
+
+					/* public email ? */
+					ss = strget(par, "pem=", 10, '&');
+					if(ss != NULL && strcmp(ss, "1") == 0) {
+						ui.Flags = ui.Flags | PROFILES_FLAG_VISIBLE_EMAIL;
+					}
+					else ui.Flags = ui.Flags & (~PROFILES_FLAG_VISIBLE_EMAIL);
+					if(ss != NULL) free(ss);
+				
+					/* save view settings to profile */
+					ss = strget(par, "vprs=", 10, '&');
+					if(ss != NULL && strcmp(ss, "1") == 0) {
+						ui.Flags = ui.Flags | PROFILES_FLAG_VIEW_SETTINGS;
+                    }
+					else ui.Flags = ui.Flags & (~PROFILES_FLAG_VIEW_SETTINGS);
+					if(ss != NULL) free(ss);
+																									
+
+					
+					if(act != NULL && strcmp(act, MESSAGEMAIN_register_register) == 0) {
+
+						Tittle_cat(TITLE_Registration);
+
+						DoCheckAndCreateProfile(&ui, &fui, passwdconfirm, oldpasswd, 1, deal);
+					}
+					else if(act != NULL && strcmp(act, MESSAGEMAIN_register_edit) == 0) {
+
+						Tittle_cat(TITLE_Registration);
+
+						DoCheckAndCreateProfile(&ui, &fui, passwdconfirm, oldpasswd, 2, deal);
+					}
+					else
+					if(act != NULL && strcmp(act, MESSAGEMAIN_register_delete) == 0) {
+
+						char* delete_confirmed = strget(par, CONFIRM_DELETE_CHECKBOX_TEXT "=", 255, '&');
+						if(!delete_confirmed || !strlen(delete_confirmed))
+							goto End_URLerror;
+						Tittle_cat(TITLE_Registration);
+
+						DoCheckAndCreateProfile(&ui, &fui, passwdconfirm, oldpasswd, 3, deal);						
+					}
+					else {
+						if(act != NULL) free(act);
+						goto End_URLerror;
+					}
+					if(act != NULL) free(act);
+					free(passwdconfirm);
+					free(oldpasswd);
+					goto End_part;
+				}
+				else goto End_URLerror;
+			}
+			free(st);
+		}
+
+		SProfile_FullUserInfo fui;
+		SProfile_UserInfo ui;
+		memset(&fui, 0, sizeof(fui));
+		fui.AboutUser = (char*)malloc(1);
+		fui.AboutUser[0] = 0;
+		memset(&ui, 0, sizeof(ui));
+		ui.Flags = USER_DEFAULT_PROFILE_CREATION_FLAGS;
+
+		DWORD x = 0;
+		if(ULogin.LU.ID[0] != 0 && (ULogin.LU.right & USERRIGHT_SUPERUSER)) x = 7;
+		else if(ULogin.LU.ID[0] == 0) x = 1;
+		else if(ULogin.LU.ID[0] != 0) x = 6;
+
+		if(x & 0x02) {
+			ULogin.uprof->GetUserByName(ULogin.pui->username, &ui, &fui, NULL);
+		}
+		else {
+			strcpy(fui.HomePage, "http://");
+		}
+
+		Tittle_cat(TITLE_Registration);
+
+		PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+		PrintEditProfileForm(&ui, &fui, x);
+
+		free(fui.AboutUser);
+
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+		goto End_part;
+	}
+
+#if	TOPICS_SYSTEM_SUPPORT
+	if(strncmp(deal, "ChangeTopic", 11) == 0) {
+		if((ULogin.LU.right & USERRIGHT_SUPERUSER) != 0) {
+		char *sn;
+		DWORD MsgNum = 0, Topic;
+		if((sn = strget(deal, "ChangeTopic=", 255 - 1, '&')) != NULL) {
+			errno = 0;
+			int errok;
+			char *ss;
+			MsgNum = strtol(sn, &ss, 10);
+			if( (!(*sn != '\0' && *ss == '\0')) || errno == ERANGE || MsgNum == 0 ||
+				(MsgNum = DB.TranslateMsgIndex(MsgNum)) == NO_MESSAGE_CODE) {
+				errok = 0;
+			}
+			else errok = 1;
+			free(sn);
+			if(errok && (st = strget(deal,"topic=", 60, '&')) != NULL) {
+				errno = 0;
+				char *ss;
+				Topic = strtol(st, &ss, 10);
+				if( (!(*st != '\0' && *ss == '\0')) || errno == ERANGE || Topic > TOPICS_COUNT) {
+					errok = 0;
+				}
+				else errok = 1;
+				free(st);
+
+				//	Do real job (change the topic)
+				SMessage mes;
+				if(ReadDBMessage(MsgNum, &mes)) {
+					DWORD oldTopic = mes.Topics;
+					mes.Topics = Topic;
+					if(WriteDBMessage(MsgNum, &mes)) {
+						PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP, mes.ViIndex, mes.ViIndex);
+						PrintBoardError(MESSAGEMAIN_messagechanged, MESSAGEMAIN_messagechanged2, HEADERSTRING_REFRESH_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_THREAD, mes.ViIndex);
+						PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAQHELP, mes.ViIndex);
+						print2log("Topic of message %d (%s (by %s)) was changed from [%s] to [%s] by %s", tmp, mes.MessageHeader, mes.AuthorName,
+							Topics_List[oldTopic], Topics_List[Topic], ULogin.pui->username);
+						goto End_part;
+					}
+				}
+			}
+		}
+
+		//	request error
+		else goto End_URLerror;
+		}
+	}
+#endif
+
+	if(strncmp(deal, "userlist", 8) == 0) {
+		char *sn;
+		DWORD code = 1; // by name
+		if((sn = strget(deal, "userlist=", 255 - 1, '&')) != NULL) {
+			errno = 0;
+			DWORD retval;
+			char *ss;
+			retval = strtol(sn, &ss, 10);
+			if( (!(*sn != '\0' && *ss == '\0')) || errno == ERANGE || retval == 0 || retval > 6) {
+
+			}
+			else code = retval;
+		}
+
+		// security check
+		if((ULogin.LU.right & USERRIGHT_VIEW_MESSAGE) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+		if(code == 2 || code == 3 || code == 4 || code == 5 || code == 6) {
+			// security check
+			if((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0) {
+				printaccessdenied(deal);
+				goto End_part;
+			}
+		}
+
+		Tittle_cat(TITLE_UserList);
+
+		PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+		PrintUserList(&DB, code);
+
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+		goto End_part;
+	}
+
+	if(strncmp(deal, "persmsgform", 11) == 0) {
+		if(ULogin.LU.UniqID != 0) {
+			// personal messages
+			char *sn = strget(deal, "persmsgform=", 255 - 1, '&');
+			if(sn) {
+				char * f = FilterHTMLTags(sn, 255-1);
+				free(sn);
+				sn = f;
+			}
+			if(!sn) {
+				sn = (char*)malloc(1000);
+				strcpy(sn, "");
+			}
+
+			Tittle_cat(TITLE_AddPrivateMsg);
+
+			PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+			PrintPrivateMessageForm(sn, "");
+
+			PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+			free(sn);
+		}
+		else {
+			Tittle_cat(TITLE_Error);
+
+			PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+			PrintBoardError(MESSAGEMAIN_privatemsg_denyunreg, MESSAGEMAIN_privatemsg_denyunreg2, 0);
+			PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+		}
+		goto End_part;
+	}
+
+	if(strncmp(deal, "persmsgpost", 11) == 0) {
+		if(ULogin.LU.UniqID != 0) {
+		// personal messages post or preview
+		int bodyok = 0, nameok = 0, tolong = 0, allowpmsg = 1;
+		
+		/* get parameters */
+		par = GetParams(MAX_PARAMETERS_STRING);
+		if(par != NULL) {
+			char *name, *body, *fbody, *todo;
+			CProfiles prof;
+			SProfile_UserInfo ui;
+			SProfile_FullUserInfo fui;
+			int preview = 0;
+
+			todo = strget(par, "Post=", MAX_PARAMETERS_STRING - 1, '&');			
+
+			if(todo != NULL && strcmp(todo, MESSAGEMAIN_privatemsg_prev_msg_btn) == 0) {
+				preview = 1;
+			}
+			else if(todo != NULL && strcmp(todo, MESSAGEMAIN_privatemsg_send_msg_btn) == 0) {
+				preview = 0;
+			}
+			else {
+				free(par);
+				printbadurl(deal);
+				goto End_part;
+			}
+
+			free(todo);
+
+			name = strget(par, "name=", PROFILES_MAX_USERNAME_LENGTH - 1, '&');
+			body = strget(par, "body=", MAX_PARAMETERS_STRING - 1, '&');
+
+			if(name && prof.GetUserByName(name, &ui, &fui, NULL) == PROFILE_RETURN_ALLOK) {
+				if((ui.Flags & PROFILES_FLAG_PERSMSGDISABLED)) allowpmsg = 0;
+				nameok = 1;
+			}
+			if(body && strlen(body) > 0) {
+				DWORD retflg;
+				if(FilterBoardTags(body, &fbody, 0, MAX_PARAMETERS_STRING - 1,
+					MESSAGE_ENABLED_SMILES | MESSAGE_ENABLED_TAGS | BOARDTAGS_TAG_PREPARSE, &retflg) == 0) {
+					/* if to long - ignore tags */
+					
+				}
+				else {
+					free(body);
+					if(strcmp(fbody, " ") == 0) *fbody = 0;
+					body = fbody;
+				}
+				if(strcmp(body, "") != 0) bodyok = 1;
+				if(strlen(body) > PROFILE_PERSONAL_MESSAGE_LENGHT - 1) tolong = 1;
+			}
+
+			if(bodyok && nameok && (!tolong) && allowpmsg) {
+				if(preview) {
+					char tostr[2000];
+					char *ss;
+
+					Tittle_cat(TITLE_AddPrivateMsg);
+
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+					printf(DESIGN_PREVIEW_PREVIEWMESSAGE "<BR>", MESSAGEHEAD_preview_preview_message);
+					DB.Profile_UserName(name, tostr, 1);
+					ss = ConvertFullTime(time(NULL));
+					// print header
+					printf("%s" MESSAGEMAIN_privatemsg_touser " %s, " MESSAGEMAIN_privatemsg_date " %s%s",
+						DESIGN_open_dl, tostr, ss, DESIGN_close_dl);
+
+					char *st = FilterHTMLTags(body, MAX_PARAMETERS_STRING - 1);
+					char *st1 = NULL;
+					DWORD retflg;
+					if(FilterBoardTags(st, &st1, 0, MAX_PARAMETERS_STRING - 1, 
+						MESSAGE_ENABLED_SMILES | MESSAGE_ENABLED_TAGS | BOARDTAGS_PURL_ENABLE |
+						BOARDTAGS_EXPAND_ENTER, &retflg) == 0)
+					{
+						st1 = st;
+						st = NULL;
+					}
+	
+					// print message text
+					printf(DESIGN_PRIVATEMSG_FRAME,	DESIGN_open_dl,
+						DESIGN_PRIVATEMSG_FRAME_BGCL_OUT, st1, DESIGN_close_dl, DESIGN_break);
+
+					PrintPrivateMessageForm(name, body);
+
+					if(st) free(st);
+					if(st1) free(st1);
+				}
+				else {
+				if(prof.PostPersonalMessage(name, 0, body, ULogin.pui->username, ULogin.LU.UniqID) == PROFILE_RETURN_ALLOK) {
+
+					Tittle_cat(TITLE_PrivateMsgWasPosted);
+
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					PrintBoardError(MESSAGEMAIN_privatemsg_msgwassent, MESSAGEMAIN_privatemsg_msgwassent2, HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+
+					// Send ackn. to recipient
+					if((ui.Flags & PROFILES_FLAG_PERSMSGTOEMAIL)) {
+						char *pb2;
+						char subj[1000];
+						char bdy[100000];
+
+						sprintf(subj, MAILACKN_PRIVATEMSG_SUBJECT, ULogin.pui->username);
+
+						if(!PrepareTextForPrint(body, &pb2, 0/*security*/, MESSAGE_ENABLED_TAGS | BOARDTAGS_EXPAND_ENTER | BOARDTAGS_PURL_ENABLE)) {
+							pb2 = (char*)malloc(strlen(body) + 1);
+							strcpy(pb2, body);
+						}
+
+						sprintf(bdy, MAILACKN_PRIVATEMSG_BODY, name, ULogin.pui->username, pb2, ULogin.pui->username);
+
+						wcSendMail(fui.Email, subj, bdy);
+						print2log("Private message mailackn was sent to %s (%s->%s)", fui.Email, ULogin.pui->username, name);
+
+						free(pb2);
+					}
+				}
+				else {
+					Tittle_cat(TITLE_Error);
+
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					PrintBoardError(MESSAGEMAIN_privatemsg_msgcantsend, MESSAGEMAIN_privatemsg_msgcantsend2, 0);
+				}
+				}
+
+				free(body);
+				free(name);
+				if(nameok) free(fui.AboutUser);
+
+				PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+				goto End_part;
+			}
+			else {
+				Tittle_cat(TITLE_AddPrivateMsg);
+
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+			}
+			if(nameok) free(fui.AboutUser);
+			// print form and errors
+			if(!allowpmsg) {
+				printf("<P><CENTER><LI> <FONT COLOR=RED><BOLD>" MESSAGEMAIN_privatemsg_disable_pmsg "</BOLD></FONT></CENTER>");
+			}
+			else {
+				if(!nameok)
+					printf("<P><CENTER><LI> <FONT COLOR=RED>" MESSAGEMAIN_privatemsg_invalid_user "</FONT></CENTER>");
+				if(!bodyok)
+					printf("<P><CENTER><LI> <FONT COLOR=RED>" MESSAGEMAIN_privatemsg_invalid_body "</FONT></CENTER>");
+				if(tolong)
+					printf("<P><CENTER><LI> <FONT COLOR=RED>" MESSAGEMAIN_privatemsg_tolong_body "</FONT></CENTER>");
+			}
+
+			if(!name) {
+				name = (char*)malloc(10);
+				*name = 0;
+			}
+			if(!name) {
+				body = (char*)malloc(10);
+				*body = 0;
+			}
+			PrintPrivateMessageForm(name, body);
+
+			PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+			free(body);
+			free(name);
+		}
+		}
+		else {
+			Tittle_cat(TITLE_Error);
+
+			PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+			PrintBoardError(MESSAGEMAIN_privatemsg_denyunreg, MESSAGEMAIN_privatemsg_denyunreg2, 0);
+			PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+		}
+		goto End_part;
+	}
+
+	if(strncmp(deal, "persmsg", 7) == 0) {
+		if(ULogin.LU.UniqID != 0) {
+		// personal messages
+		char *sn;
+		DWORD type = 0;
+		if((sn = strget(deal, "persmsg=", 255 - 1, '&')) != NULL) {
+			if(strcmp(sn, "all") == 0) {
+				type = 1;
+			}
+			free(sn);
+		}
+
+		CProfiles prof;
+		SPersonalMessage *msg, *frommsg;
+		DWORD *tt, *ft;
+		if(type) {
+			tt = NULL;
+			ft = NULL;
+		}
+		else {
+			tt = (DWORD*)malloc(sizeof(DWORD));
+			*tt = 10;
+			ft = (DWORD*)malloc(sizeof(DWORD));
+			*ft = 0;
+		}
+		// let's read to messages (maybe from too)
+		if(prof.ReadPersonalMessages(NULL, ULogin.LU.SIndex, &msg, tt, &frommsg, ft) != PROFILE_RETURN_ALLOK)
+			printhtmlerror();
+
+		// let's get received message count
+		DWORD cnt = 0, postedcnt = 0;
+		if(msg) {
+			while(msg[cnt].Prev != 0xffffffff) cnt++;
+			cnt++;
+		}
+
+		if(ft) {
+			if(cnt) {
+				SPersonalMessage *msg1;
+				time_t ld = msg[cnt-1].Date;
+
+				if(prof.ReadPersonalMessagesByDate(NULL, ULogin.LU.SIndex, &msg1, 0, &frommsg, ld) != PROFILE_RETURN_ALLOK)
+					printhtmlerror();
+
+				// let's get posted message count
+				if(frommsg) {
+					while(frommsg[postedcnt].Prev != 0xffffffff) postedcnt++;
+					postedcnt++;
+				}
+			}
+			else {
+				*ft = 10;
+				// let's read to messages (maybe from too)
+				if(prof.ReadPersonalMessages(NULL, ULogin.LU.SIndex, &msg, NULL, &frommsg, ft) != PROFILE_RETURN_ALLOK)
+					printhtmlerror();
+				// let's get posted message count
+				if(frommsg) {
+					while(frommsg[postedcnt].Prev != 0xffffffff) postedcnt++;
+					postedcnt++;
+				}
+			}
+		}
+		else {
+			// let's get posted message count
+			if(frommsg) {
+				while(frommsg[postedcnt].Prev != 0xffffffff) postedcnt++;
+				postedcnt++;
+			}
+		}
+
+		Tittle_cat(TITLE_PrivateMsg);
+
+		PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_PRIVATEMSG, MAINPAGE_INDEX);
+
+		char uuname[1000];
+		DB.Profile_UserName(ULogin.pui->username, uuname, 1);
+
+		printf("<BR><BR><CENTER><B>" MESSAGEMAIN_privatemsg_header " %s</B><BR>", uuname);
+		if((ULogin.pui->Flags & PROFILES_FLAG_PERSMSGDISABLED))
+			printf("<U>" MESSAGEMAIN_privatemsg_disabled "</U><BR>");
+
+		if(cnt) printf(MESSAGEMAIN_privatemsg_newmsgcnt " %d, ",
+			ULogin.pui->persmescnt - ULogin.pui->readpersmescnt);
+		else printf(MESSAGEMAIN_privatemsg_nonewmsg ", ");
+		printf(MESSAGEMAIN_privatemsg_allmsgcnt " %d, " MESSAGEMAIN_privatemsg_allmsgcnt1 " %d<BR>"
+			"<A HREF=\"" MY_CGI_URL "?persmsgform\" STYLE=\"text-decoration:underline;\">" MESSAGEMAIN_privatemsg_writenewmsg
+			"</A></CENTER><P><P>", ULogin.pui->persmescnt, ULogin.pui->postedmescnt);
+
+		char tostr[1000], newm[100], *nickurl;
+		char *ss;
+		SPersonalMessage *pmsg;
+		int i = 0;
+		int j = 0;
+		int received = 0;	// posted or received
+		for(;;) {
+			// check exit expression
+			if(i == cnt && j == postedcnt) break;
+			if(i == cnt) {
+				pmsg = &(frommsg[j]);
+				j++;
+				received = 0;
+			} else {
+				if(j == postedcnt) {
+					pmsg = &(msg[i]);
+					i++;
+					received = 1;
+				}
+				else {
+					if(frommsg[j].Date > msg[i].Date) {
+						pmsg = &(frommsg[j]);
+						j++;
+						received = 0;
+					}
+					else {
+						pmsg = &(msg[i]);
+						i++;
+						received = 1;
+					}
+				} 
+			}
+
+			if(!received) {
+				DB.Profile_UserName(pmsg->NameTo, tostr, 1);
+			}
+			else {
+				DB.Profile_UserName(pmsg->NameFrom, tostr, 1);
+			}
+
+			ss = ConvertFullTime(pmsg->Date);
+
+			if(received && i <= (ULogin.pui->persmescnt - ULogin.pui->readpersmescnt))
+				strcpy(newm, MESSAGEMAIN_privatemsg_newmark);
+			else strcpy(newm, "");
+
+			if(!received) {
+				// posted message
+				printf("%s" MESSAGEMAIN_privatemsg_touser " %s, " MESSAGEMAIN_privatemsg_date " %s%s",
+					DESIGN_open_dl, tostr, ss, DESIGN_close_dl);
+			}
+			else {
+				nickurl = CodeHttpString(pmsg->NameFrom, 0);
+				// received message
+				if(nickurl) {
+					printf("%s" MESSAGEMAIN_privatemsg_fromuser " %s, " MESSAGEMAIN_privatemsg_date
+						" %s <A HREF=\"" MY_CGI_URL "?persmsgform=%s\" STYLE=\"text-decoration:underline;\">" MESSAGEMAIN_privatemsg_answer "</A> %s%s",
+						DESIGN_open_dl, tostr, ss, nickurl, newm, DESIGN_close_dl);
+				}
+			}
+
+			char *st = FilterHTMLTags(pmsg->Msg, MAX_PARAMETERS_STRING - 1);
+			char *st1 = NULL;
+			DWORD retflg;
+			if(FilterBoardTags(st, &st1, 0, MAX_PARAMETERS_STRING - 1, 
+				MESSAGE_ENABLED_SMILES | MESSAGE_ENABLED_TAGS | BOARDTAGS_PURL_ENABLE |
+				BOARDTAGS_EXPAND_ENTER, &retflg) == 0)
+			{
+				st1 = st;
+				st = NULL;
+			}
+
+			printf(DESIGN_PRIVATEMSG_FRAME,	DESIGN_open_dl,
+				received ? DESIGN_PRIVATEMSG_FRAME_BGCL_IN : DESIGN_PRIVATEMSG_FRAME_BGCL_OUT, st1, DESIGN_close_dl, DESIGN_break);
+
+			if(st) free(st);
+			if(st1) free(st1);
+		}
+
+		ULogin.pui->readpersmescnt = ULogin.pui->persmescnt;
+		prof.SetUInfo(ULogin.LU.SIndex, ULogin.pui);
+
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_PRIVATEMSG, MAINPAGE_INDEX);
+		if(msg) free(msg);
+		if(frommsg) free(frommsg);
+		}
+		else {
+			Tittle_cat(TITLE_Error);
+
+			PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+			PrintBoardError(MESSAGEMAIN_privatemsg_denyunreg, MESSAGEMAIN_privatemsg_denyunreg2, 0);
+			PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+		}
+		goto End_part;
+	}
+
+	if(strncmp(deal, "globann", 7) == 0) {
+		if((ULogin.LU.right & USERRIGHT_POST_GLOBAL_ANNOUNCE) != 0) {
+			// post global announce or global announce form
+			char *sn;
+			DWORD type = 0;
+			if((sn = strget(deal, "globann=", 255 - 1, '&')) != NULL) {
+				if(strcmp(sn, "post") == 0) {
+					type = 1;
+					free(sn);
+				}
+			}
+			if(!type) {
+				Tittle_cat(TITLE_PostGlobalAnnounce);
+
+				char *ss, body[GLOBAL_ANNOUNCE_MAXSIZE];
+				int cgann_num;
+				cgann_num = strtol(sn, &ss, 10);
+				if( (!(*sn != '\0' && *ss == '\0')) || errno == ERANGE) {
+					cgann_num = 0;
+				}
+				free(sn);
+
+				body[0] = 0;
+				if(cgann_num != 0) {
+					SGlobalAnnounce *ga;
+					DWORD cnt, i;
+					if(ReadGlobalAnnounces(0, &ga, &cnt) != ANNOUNCES_RETURN_OK) printhtmlerror();
+					for(i = 0; i < cnt; i++) {
+						if(ga[i].Number == cgann_num) {
+							strcpy(body, ga[i].Announce);
+						}
+					}
+				}
+
+				// print form
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+				PrintAnnounceForm(body, cgann_num);
+
+				PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+				goto End_part;
+			}
+			else {
+				char *body = NULL;
+				int cgann_num = 0, preview = 0, refid = 0;
+
+				// post
+				/* get parameters */
+				par = GetParams(MAX_PARAMETERS_STRING);
+				if(par) {
+					char *todo = strget(par, "Post=", MAX_PARAMETERS_STRING - 1, '&');
+
+					// preview or post ?
+					if(todo != NULL && strcmp(todo, MESSAGEMAIN_globann_prev_ann_btn) == 0) {
+						preview = 1;
+					}
+					else if(todo != NULL && strcmp(todo, MESSAGEMAIN_globann_send_ann_btn) == 0) {
+						preview = 0;
+					}
+					else {
+						free(par);
+						printbadurl(deal);
+						goto End_part;
+					}
+					free(todo);
+
+					char *sn = strget(par, "cgann=", 255 - 1, '&');
+					char *refids = strget(par, "refid=", 100, '&');
+					if(refids) {
+						if(strcmp(refids, "1") == 0) refid = 1;
+						free(refids);
+					}
+					body = strget(par, "body=", MAX_PARAMETERS_STRING - 1, '&');
+					// translate to numeric format
+					char *ss;
+					if(sn) {
+						cgann_num = strtol(sn, &ss, 10);
+						if( (!(*sn != '\0' && *ss == '\0')) || errno == ERANGE) {
+							cgann_num = 0;
+						}
+						free(sn);
+					}
+					free(par);
+				}
+				if(body && strlen(body) > 5) {
+					if(strlen(body) >= GLOBAL_ANNOUNCE_MAXSIZE - 1) {
+
+						Tittle_cat(TITLE_PostGlobalAnnounce);
+
+						PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+						printf("<P><CENTER><LI> <FONT COLOR=RED>" MESSAGEMAIN_globann_tolong "</FONT></CENTER>");
+
+						PrintAnnounceForm(body, cgann_num);
+
+						PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					}
+					else {
+						if(preview) {
+							char uname[1000];
+							char *st;
+							char date[1000];
+
+							DB.Profile_UserName(ULogin.pui->username, uname, 1);
+							PrepareTextForPrint(body, &st, 0, MESSAGE_ENABLED_SMILES | MESSAGE_ENABLED_TAGS |
+								BOARDTAGS_PURL_ENABLE | BOARDTAGS_EXPAND_ENTER);
+							ConvertTime(time(NULL), date);
+
+							Tittle_cat(TITLE_PostGlobalAnnounce);
+
+							PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+							printf("<BR><BR><CENTER><B>%s</B></CENTER>", MESSAGEMAIN_globann_preview_hdr);
+
+							printf(DESIGN_GLOBALANN_FRAME, DESIGN_open_dl, st, MESSAGEMAIN_globann_postedby,
+								uname, date, "", DESIGN_close_dl);
+
+							PrintAnnounceForm(body, cgann_num);
+
+							PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+							if(st) free(st);
+						}
+						else {
+							if( (cgann_num && (!refid)) ? UpdateGlobalAnnounce(cgann_num, ULogin.pui->username,
+								ULogin.pui->UniqID, body, 0, 0,
+								ANNOUNCES_UPDATE_OPT_USER | ANNOUNCES_UPDATE_OPT_TIME |
+								ANNOUNCES_UPDATE_OPT_TTL | ANNOUNCES_UPDATE_OPT_FLAGS) !=
+								ANNOUNCES_RETURN_OK
+								: PostGlobalAnnounce(ULogin.pui->username, ULogin.pui->UniqID, body,
+								0, 0) != ANNOUNCES_RETURN_OK )
+							{
+								Tittle_cat(TITLE_Error);
+
+								PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+								PrintBoardError(MESSAGEMAIN_globann_anncantsend, MESSAGEMAIN_globann_anncantsend2, 0);
+								PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+							}
+							else {
+								Tittle_cat(TITLE_GlobalAnnWasPosed);
+
+								if(cgann_num && refid) {
+									DeleteGlobalAnnounce(cgann_num, 0);
+									print2log("Announce %d was deleted during update", cgann_num);
+								}
+
+								if(!cgann_num) {
+									PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+									PrintBoardError(MESSAGEMAIN_globann_annwassent, MESSAGEMAIN_globann_annwassent2, HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+									PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+								}
+								else {
+									PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+									PrintBoardError(MESSAGEMAIN_globann_annwasupdated, MESSAGEMAIN_globann_annwasupdated2, HEADERSTRING_REFRESH_TO_MAIN_PAGE);
+									PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, MAINPAGE_INDEX);
+								}
+
+								print2log("Global announce (%s) was posted by %s", body, ULogin.pui->username);
+							}
+						}
+					}
+				}
+				else if(body) {
+					Tittle_cat(TITLE_PostGlobalAnnounce);
+
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+					printf("<P><CENTER><LI> <FONT COLOR=RED>" MESSAGEMAIN_globann_toshort "</FONT></CENTER>");
+
+					if(body) PrintAnnounceForm(body, cgann_num);
+					else PrintAnnounceForm("", cgann_num);
+
+					PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+				}
+				else {
+					// invalid request
+					printbadurl(deal);
+				}
+				goto End_part;
+			}
+		}
+		else {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+	}
+
+	if(strncmp(deal, "ganndel", 7) == 0) {
+		char *sn;
+		if((ULogin.LU.right & USERRIGHT_POST_GLOBAL_ANNOUNCE) != 0) {
+			DWORD MsgNum = 0;
+			if((sn = strget(deal, "ganndel=", 255 - 1, '&')) != NULL) {
+				errno = 0;
+				int errok;
+				char *ss;
+				MsgNum = strtol(sn, &ss, 10);
+				if( (!(*sn != '\0' && *ss == '\0')) || errno == ERANGE) {
+					errok = 0;
+				}
+				else errok = 1;
+				free(sn);
+
+				if(errok) {
+					if(DeleteGlobalAnnounce(MsgNum, ((ULogin.LU.right & USERRIGHT_SUPERUSER) != 0) ? 0 : ULogin.LU.UniqID) == ANNOUNCES_RETURN_OK) {
+						Tittle_cat(TITLE_GlobalAnnWasDeleted);
+
+						print2log("Global Announce %d was deleted by user %s", MsgNum, ULogin.pui->username);
+						PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+						PrintBoardError(MESSAGEMAIN_globann_wasdeleted, MESSAGEMAIN_globann_wasdeleted2, 0);
+						PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					}
+					else {
+						Tittle_cat(TITLE_Error);
+
+						print2log("Global Announce %d cannot be deleted by user %s", MsgNum, ULogin.pui->username);
+						PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+						PrintBoardError(MESSAGEMAIN_globann_cannotdel, MESSAGEMAIN_globann_cannotdel2, 0);
+						PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					}
+				}
+				else {
+					Tittle_cat(TITLE_Error);
+
+					PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+					PrintBoardError(MESSAGEMAIN_globann_invalidnum, MESSAGEMAIN_globann_invalidnum2, 0);
+					PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+				}
+			}
+			goto End_part;
+		}
+	}
+
+	if(strncmp(deal, "rann", 4) == 0) {
+		char *sn;
+		if((ULogin.LU.right & USERRIGHT_VIEW_MESSAGE) != 0) {
+			DWORD MsgNum = 0;
+			if((sn = strget(deal, "rann=", 255 - 1, '&')) != NULL) {
+				errno = 0;
+				int errok;
+				char *ss;
+				MsgNum = strtol(sn, &ss, 10);
+				if( (!(*sn != '\0' && *ss == '\0')) || errno == ERANGE) {
+					errok = 0;
+				}
+				else errok = 1;
+				free(sn);
+
+				if(!errok) goto End_URLerror;
+
+				currentlann = MsgNum;
+				// to main page at once
+				PrintHTMLHeader(HEADERSTRING_REDIRECT_NOW | HEADERSTRING_NO_CACHE_THIS, MAINPAGE_INDEX);
+				goto End_part;
+			}
+		}
+	}
+
+#ifdef USER_FAVOURITES_SUPPORT
+	if(strncmp(deal, "favs", 4) == 0) {
+		int num;
+		if(ULogin.LU.UniqID != 0) {
+			CProfiles prof;
+			//favourites
+			// security check
+			if((ULogin.LU.right & USERRIGHT_VIEW_MESSAGE) == 0) {
+				printaccessdenied(deal);
+				goto End_part;
+			}
+			Tittle_cat(TITLE_FavouritesPage);
+			PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAVOURITES, MAINPAGE_INDEX);
+			printf("<P><CENTER><P><B>%s</B><BR></CENTER>", MESSAGEHEAD_favourites);
+
+			int updated;
+			if( (num = DB.PrintandCheckMessageFavsExistandInv(ULogin.pui,
+				ULogin.LU.right & USERRIGHT_SUPERUSER, &updated)) == 0)
+				printf("<P><CENTER><B>" MESSAGEMAIN_favourites_listclear "</B></CENTER><P>");
+			if(updated) prof.SetUInfo(ULogin.LU.SIndex, ULogin.pui);
+			PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_DISABLE_FAVOURITES, MAINPAGE_INDEX);
+			goto End_part;
+		}
+		else {
+			Tittle_cat(TITLE_Error);
+			PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+			PrintBoardError(MESSAGEMAIN_favourites_denyunreg, MESSAGEMAIN_favourites_denyunreg2, 0);
+			PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+		}
+		goto End_part;
+	}
+	
+	if(strncmp(deal, "favadd", 6) == 0) {
+		if(ULogin.LU.UniqID != 0){
+			if((ULogin.LU.right & USERRIGHT_VIEW_MESSAGE) == 0) {
+				printaccessdenied(deal);
+				goto End_part;
+			}
+			if((st = strget(deal, "favadd=", 255 - 1, '&')) != NULL) {
+				errno = 0;
+				DWORD addmsg;
+				char *ss;
+				addmsg = strtol(st, &ss, 10);
+				if( (!(*st != '\0' && *ss == '\0')) || errno == ERANGE  || addmsg < 1){
+					free (st);
+					 goto End_URLerror;
+				}
+				free (st);
+				DWORD msg;
+				if( ( msg=DB.TranslateMsgIndex(addmsg)) == NO_MESSAGE_CODE){
+					printnomessage(deal);
+					goto End_part;
+				}
+				if(!ReadDBMessage(msg, &mes)) printhtmlerror();
+				/* allow read invisible message only to SUPERUSER */
+				if((mes.Flag & MESSAGE_IS_INVISIBLE) && ((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0)) {
+					printnomessage(deal);
+					goto End_part;
+				}
+#if USER_FAVOURITES_SUPPORT == 2
+				if( mes.ParentThread != 0){
+						Tittle_cat(TITLE_FavouritesPageAdd);
+						PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+						PrintBoardError(MESSAGEMAIN_favourites_addno, MESSAGEMAIN_favourites_addnoparent, 0);
+						PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+						goto End_part;
+				}
+#endif
+				CProfiles prof;
+				int result = prof.CheckandAddFavsList(ULogin.LU.SIndex, addmsg, 1);
+				switch(result) {
+					case PROFILE_RETURN_ALLOK:
+						Tittle_cat(TITLE_FavouritesPageAdd);
+						PrintHTMLHeader(HEADERSTRING_DISABLE_ALL, 0);
+						PrintBoardError(MESSAGEMAIN_favourites_added, MESSAGEMAIN_favourites_added2, 0);
+						PrintBottomLines(HEADERSTRING_DISABLE_ALL, 0);
+						goto End_part;
+					case PROFILE_RETURN_ALREADY_EXIST:
+						Tittle_cat(TITLE_FavouritesPageAdd);
+						PrintHTMLHeader(HEADERSTRING_DISABLE_ALL, 0);
+						PrintBoardError(MESSAGEMAIN_favourites_addno, MESSAGEMAIN_favourites_addexist, 0);
+						PrintBottomLines(HEADERSTRING_DISABLE_ALL, 0);
+						goto End_part;
+					case PROFILE_RETURN_UNKNOWN_ERROR:
+						Tittle_cat(TITLE_FavouritesPageAdd);
+						PrintHTMLHeader(HEADERSTRING_DISABLE_ALL, 0);
+						PrintBoardError(MESSAGEMAIN_favourites_addno, MESSAGEMAIN_favourites_addnoplace, 0);
+						PrintBottomLines(HEADERSTRING_DISABLE_ALL, 0);
+						goto End_part;
+					default:
+						printhtmlerror();
+						goto End_part;
+					
+				}
+			}
+		}
+		else {
+			Tittle_cat(TITLE_Error);
+			PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+			PrintBoardError(MESSAGEMAIN_favourites_denyunreg, MESSAGEMAIN_favourites_denyunreg2, 0);
+			PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+		}
+		goto End_part;
+	}
+
+	if(strncmp(deal, "favdel", 6) == 0) {
+		if(ULogin.LU.UniqID != 0){
+			if((ULogin.LU.right & USERRIGHT_VIEW_MESSAGE) == 0) {
+				printaccessdenied(deal);
+				goto End_part;
+			}
+			if((st = strget(deal, "favdel=", 255 - 1, '&')) != NULL) {
+				errno = 0;
+				DWORD delmsg;
+				char *ss;
+				delmsg = strtol(st, &ss, 10);
+				if( (!(*st != '\0' && *ss == '\0')) || errno == ERANGE  || delmsg == 0){
+					free (st);
+					 goto End_URLerror;
+				}
+				free (st);
+				DWORD msg;
+				if( (msg = DB.TranslateMsgIndex(delmsg)) == NO_MESSAGE_CODE){
+					printnomessage(deal);
+					goto End_part;
+				}
+				if(!ReadDBMessage(msg, &mes)) printhtmlerror();
+				/* allow read invisible message only to SUPERUSER */
+				if((mes.Flag & MESSAGE_IS_INVISIBLE) && ((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0)) {
+					printnomessage(deal);
+					goto End_part;
+				}
+				CProfiles prof;
+				int result = prof.DelFavsList(ULogin.LU.SIndex, delmsg);
+				switch(result) {
+					case PROFILE_RETURN_ALLOK:
+						Tittle_cat(TITLE_FavouritesPageDel);
+						PrintHTMLHeader(HEADERSTRING_DISABLE_ALL, 0);
+						PrintBoardError(MESSAGEMAIN_favourites_deleted, MESSAGEMAIN_favourites_deleted2, 0);
+						PrintBottomLines(HEADERSTRING_DISABLE_ALL, 0);
+						goto End_part;
+					case PROFILE_RETURN_UNKNOWN_ERROR:
+						Tittle_cat(TITLE_FavouritesPageDel);
+						PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+						PrintBoardError(MESSAGEMAIN_favourites_delno,  MESSAGEMAIN_favourites_delnoexist, 0);
+						PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+						goto End_part;
+					default:
+						printhtmlerror();
+						goto End_part;
+					
+				}
+			}
+		}
+		else {
+			Tittle_cat(TITLE_Error);
+			PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+			PrintBoardError(MESSAGEMAIN_favourites_denyunreg, MESSAGEMAIN_favourites_denyunreg2, 0);
+			PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+		}
+		goto End_part;
+	}
+#endif
+
+#ifdef CLEANUP_IDLE_USERS
+
+#define DAY (60*60*24)
+#define YEAR (DAY*365)
+	if(strncmp(deal, "cluserlist", 10) == 0) {
+		bool fDelete = false;
+		if(!(ULogin.LU.right & USERRIGHT_SUPERUSER)) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+		if((st = strget(deal,"cluserlist=", 14, '&')) != NULL) {
+			if(strcmp(st, "yes") == 0) {
+				free(st);
+				fDelete = true;
+			}
+		}
+		time_t tn = time(NULL);
+		DWORD i = 0, ii=0;
+		char **buf = NULL;
+		char name[1000];
+		DWORD uc = 0;
+		CUserLogin ULogin;
+		CProfiles uprof;
+		Tittle_cat(TITLE_UserList);
+        PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+
+		printf("<BR><BR><center>");
+		printf(
+			"<font color=\"red\">%s</font><br>\n",
+			fDelete ?
+			"╤ыхфє■∙шх яюы№чютрЄхыш с√ыш єёях°эю єфрыхэ√:" : 
+		"╤яшёюъ яюы№чютрЄхыхщ яюфыхцр∙шї єфрыхэш■:"
+		);
+		if(!uprof.GenerateUserList(&buf, &uc)) {
+			printf("error generating list");
+		} else {
+			qsort((void*)buf, uc, sizeof(char*), cmp_name);
+			for(i = 0; i < uc; i++) {
+		    		DWORD 
+					PostCount = *((DWORD*)(buf[i] + 4)),
+					RefreshCount = *((DWORD*)(buf[i] + 12)),
+					UserRight =  *((DWORD*)(buf[i] + 16)),
+					LoginDate = *((DWORD*)(buf[i] + 8)),
+					activity = PostCount + RefreshCount;
+				char *username = buf[i] + 20;
+				int
+					idletime = tn - LoginDate;
+				bool
+					fSuperuser = UserRight & USERRIGHT_SUPERUSER,
+					fAged1 = idletime > YEAR,
+				 	fAged2 = idletime > YEAR / 2 &&	activity < 100,
+					fAged3 = idletime > YEAR / 4 && activity < 10;
+				if(!fSuperuser && (fAged1 || fAged2 || fAged3)) {	
+					if((ii % 10) != 0) printf(" | ");
+					if(((ii % 10) == 0) && ii != 0) printf("<br>");
+					DB.Profile_UserName(buf[i] + 20, name, 1, 1);
+					printf("%s", name);
+					if(fDelete) {
+						DWORD err = uprof.DeleteUser(username);
+						if(err == PROFILE_RETURN_ALLOK) {
+							printf("!");
+						} else { 
+							printf("═хтючьюцэю єфрышЄ№ '%s' !!!", name);
+							goto End_part;
+						}
+					}
+					ii++;
+				}// if(!fSuperuser && (fAged1 || fAged2 || fAged3)
+				free(buf[i]);
+			} //for(;i<uc;)
+			if(fDelete) {
+				printf(
+					"<br /> <b>єфрыхэю %d шч %d яюы№чютрЄхыхщ</b> \n", 
+					ii, 
+					uc);
+			} else {
+				printf(
+					"<br /> <b>┴єфхЄ єфрыхэю <fonc color=red>%d</font> шч %d яюы№чютрЄхыхщ</b> \n",
+					ii, 
+					uc);
+				printf(
+					"<br /><a href=\"" MY_CGI_URL "?cluserlist=yes\">"
+					"<font color=\"red\">╧ЁюфюыцшЄ№ ?</font></a>");
+			}
+		}//if(generate_list(..))
+		PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, MAINPAGE_INDEX);
+		goto End_part;
+	}//if(strcmp(deal,"cluserlist")) 	
+#endif //CLEANUP_IDLE_USERS
+
+
+	if(strncmp(deal, "banlist", 7) == 0) {
+		
+		/* security check */
+		if((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0) {
+			printaccessdenied(deal);
+			goto End_part;
+		}
+		if((st = strget(deal,"banlist=", 30, '&')) != NULL) {
+			if(strcmp(st, "save") == 0) {
+				// read ban list
+				par = GetParams(MAX_PARAMETERS_STRING);
+				char *ban_list;
+				ban_list = strget(par,"ban_list=", MAX_PARAMETERS_STRING, '&');
+				// this is needed because of char #10 filtering.
+				// in WIN32 printf() works incorrectly with it
+#if defined(WIN32)
+				char *mb;
+				FilterMessageForPreview(ban_list, &mb);
+				free(ban_list);
+				ban_list = mb;
+#endif
+				
+				// check ban_list is empty
+				if(ban_list == NULL || *ban_list == 0) {
+					Tittle_cat(TITLE_BanSave);
+					PrintHTMLHeader(HEADERSTRING_DISABLE_ALL, 0);
+					PrintBoardError(MESSAGEMAIN_ban_no_save, MESSAGEMAIN_ban_empty, 0);
+					PrintBottomLines(HEADERSTRING_DISABLE_ALL, 0);
+					goto End_part;
+			
+				}
+				
+				WCFILE *BAN_FILE;
+				if ((BAN_FILE = wcfopen(F_BANNEDIP, FILE_ACCESS_MODES_RW)) == NULL) printhtmlerror();
+				lock_file(BAN_FILE);
+				
+				if ( !fCheckedWrite(ban_list, strlen(ban_list), BAN_FILE)  )  {
+					unlock_file(BAN_FILE);
+					printhtmlerror();
+				}
+
+
+#ifdef WIN32	
+				wctruncate(BAN_FILE, strlen(ban_list));
+#else
+				truncate(F_BANNEDIP, strlen(ban_list));
+#endif
+
+				unlock_file(BAN_FILE);
+				wcfclose(BAN_FILE);
+				
+				Tittle_cat(TITLE_BanSave);
+				PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, 0);
+				PrintBoardError(MESSAGEMAIN_ban_save, MESSAGEMAIN_ban_save2, 0);
+				PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE | HEADERSTRING_REFRESH_TO_MAIN_PAGE, 0);
+
+				print2log("Banlist update by %s from %s", ULogin.pui->username, Cip);
+			
+			}	
+		}
+		else{
+
+			PrintHTMLHeader(HEADERSTRING_RETURN_TO_MAIN_PAGE, 0);
+			PrintBanList();
+			PrintBottomLines(HEADERSTRING_RETURN_TO_MAIN_PAGE, 0);
+
+			print2log("Banlist view by %s from %s", ULogin.pui->username, Cip);
+		}
+		goto End_part;
+	}
+	
+	
+	
+	if(strncmp(deal, "clsession1", 9) == 0) {
+		if(ULogin.LU.UniqID != 0) {
+		DWORD closeseq[2];
+		if((st= strget(deal, "clsession1=", 255 - 1, '&')) != NULL) {
+			errno = 0;
+			char *ss;
+			 closeseq[0] = strtol(st, &ss, 10);
+			if( (!(*st != '\0' && *ss == '\0')) || errno == ERANGE ||  closeseq[0] == 0 ) {
+				free(st);
+				goto End_URLerror;
+			}
+		}
+		free(st);
+		if((st= strget(deal, "clsession2=", 255 - 1, '&')) != NULL) {
+			errno = 0;
+			char *ss;
+			 closeseq[1] = strtol(st, &ss, 10);
+			if( (!(*st != '\0' && *ss == '\0')) || errno == ERANGE ||  closeseq[1] == 0 ) {
+				free(st);
+				goto End_URLerror;
+			}
+		}
+		free(st);
+
+		// checking session exists and user have suff. rights
+		// superuser knows if session does not exits
+		// user can receive only access deny message (session bf aware)
+
+		if((ULogin.LU.right & USERRIGHT_SUPERUSER) == 0){
+			if( (ULogin.LU.right & USERRIGTH_PROFILE_MODIFY) == 0 || ULogin.CheckSession(closeseq, 0, ULogin.LU.UniqID) != 1) {
+				printaccessdenied(deal);
+				goto End_part;
+			}
+		}
+		else {
+			if( ULogin.CheckSession(closeseq, 0, 0) != 1) {
+				Tittle_cat(TITLE_ClSession);
+				PrintHTMLHeader(HEADERSTRING_DISABLE_ALL | HEADERSTRING_REFRESH_TO_MAIN_PAGE, 0);
+				PrintBoardError(MESSAGEMAIN_session_closed_no, MESSAGEMAIN_session_check_failed, 0);
+				PrintBottomLines(HEADERSTRING_DISABLE_ALL | HEADERSTRING_REFRESH_TO_MAIN_PAGE, 0);
+				goto End_part;
+			}
+		}
+
+		// force closing session
+		if(ULogin.ForceCloseSessionBySeq(closeseq)){
+			Tittle_cat(TITLE_ClSession);
+			PrintHTMLHeader(HEADERSTRING_DISABLE_ALL | HEADERSTRING_REFRESH_TO_MAIN_PAGE, 0);
+			PrintBoardError(MESSAGEMAIN_session_closed_ok, MESSAGEMAIN_session_closed_ok2, 0);
+			PrintBottomLines(HEADERSTRING_DISABLE_ALL | HEADERSTRING_REFRESH_TO_MAIN_PAGE, 0);
+			goto End_part;
+		}
+		else {
+			Tittle_cat(TITLE_ClSession);
+			PrintHTMLHeader(HEADERSTRING_DISABLE_ALL | HEADERSTRING_REFRESH_TO_MAIN_PAGE, 0);
+			PrintBoardError(MESSAGEMAIN_session_closed_no, MESSAGEMAIN_session_close_failed, 0);
+			PrintBottomLines(HEADERSTRING_DISABLE_ALL | HEADERSTRING_REFRESH_TO_MAIN_PAGE, 0);
+			goto End_part;
+		}
+		}
+		goto End_URLerror;
+		
+	}
+	
+
+End_URLerror:
+	printbadurl(deal);
+
+End_part:
+
+#if _DEBUG_ == 1
+	//print2log("Exit success");
+#ifdef WIN32
+#ifdef _DEBUG
+	free(Cip);
+	free(deal);
+	free(ConfTitle);
+	_CrtDumpMemoryLeaks();
+#endif
+#endif // WIN32
+#endif // _DEBUG_
+
+	return EXIT_SUCCESS;
+}
blob - /dev/null
blob + 4c1a0a7a04688bf32036cf68a5ec17d77ec03759 (mode 644)
--- /dev/null
+++ src/main.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+                          main.h  -  main module include
+                             -------------------
+    begin                : Wed Mar 14 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef MAIN_H_INCLUDED
+#define MAIN_H_INCLUDED
+
+// bit mask for proc making html header of board
+#define HEADERSTRING_POST_NEW_MESSAGE		0x000001
+#define HEADERSTRING_CONFIGURE				0x000002
+#define HEADERSTRING_RETURN_TO_MAIN_PAGE 	0x000004
+#define HEADERSTRING_REFRESH_TO_MAIN_PAGE	0x000008
+#define HEADERSTRING_WELCOME_INFO			0x000010
+#define HEADERSTRING_DISABLE_FAQHELP		0x000020
+#define HEADERSTRING_DISABLE_LOGOFF			0x000040
+#define HEADERSTRING_DISABLE_SEARCH			0x000080
+#define HEADERSTRING_DISABLE_REGISTER		0x000100
+#define HEADERSTRING_DISABLE_LOGIN			0x000200
+#define HEADERSTRING_DISABLE_ALL			0x000400
+#define HEADERSTRING_REG_USER_LIST			0x000800
+#define HEADERSTRING_REFRESH_TO_THREAD		0x001000
+#define HEADERSTRING_ENABLE_TO_MESSAGE		0x002000
+#define HEADERSTRING_ENABLE_RESETNEW		0x004000
+#define HEADERSTRING_REDIRECT_NOW			0x008000
+#define HEADERSTRING_NO_CACHE_THIS			0x010000
+#define HEADERSTRING_DISABLE_PRIVATEMSG		0x020000
+#define HEADERSTRING_DISABLE_FAVOURITES		0x040000
+#define HEADERSTRING_DISABLE_END_TABLE		0x080000
+#define HEADERSTRING_ENABLE_REPLY_LINK		0x100000
+
+// button codes
+#define ACTION_BUTTON_POST			0x0001
+#define ACTION_BUTTON_PREVIEW		0x0002
+#define ACTION_BUTTON_EDIT			0x0004
+#define ACTION_BUTTON_FAKEREPLY		0x0008
+
+#define MAX_DELTA_POST_MESSAGE	15000
+
+#define MAINPAGE_INDEX 0xFFFFFFFF
+
+#define VERSION		"2.0 PRE BETA4"
+
+
+#endif
blob - /dev/null
blob + 8e98e268117cfa3b98d4d189c39a4ddc03d1f0b0 (mode 644)
--- /dev/null
+++ src/messages.h
@@ -0,0 +1,902 @@
+ /***************************************************************************
+                          messages.h  -  ┬ёх ёююс∙хэш  ъюэЇхЁхэЎшш
+                             -------------------
+    begin                : Fri Mar 23 2001
+    яхЁхтюф		 : └ыхъёрэфЁ ├ы ъют <vektor@3ka.mipt.ru>
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef MESSAGES_H_INCLUDED
+#define MESSAGES_H_INCLUDED
+
+#include "basetypes.h"
+
+/* ъюэёЄрэЄ√ ёт чрээ√х ёю тЁхьхэхь
+ * 0,1,2,3 -> ўрё фхэ№ эхфхы  ьхё Ў
+ */
+extern char *MESSAGEHEAD_timetypes[4];
+
+#define MESSAGEHEAD_preview_preview_message	"╧ЁхфтрЁшЄхы№э√щ яЁюёьюЄЁ"
+#define MESSAGEHEAD_preview_change_message	""
+
+#define MESSAGEHEAD_configure 				"═рёЄЁющъш"
+#define MESSAGEHEAD_resetnew				"╤сЁюёшЄ№ +"
+#define	MESSAGEHEAD_post_new_message 		"═ютюх ёююс∙хэшх"
+#define MESSAGEHEAD_return_to_main_page		"═р уыртэє■ ёЄЁрэшЎє"
+#define MESSAGEHEAD_logoff					"┬√їюф"
+#define MESSAGEHEAD_help_showhelp			"╧Ёртшыр"
+#define MESSAGEHEAD_register				"╨хушёЄЁрЎш "
+#define MESSAGEHEAD_registerprf				"┬р° яЁюЇрщы"
+#define MESSAGEHEAD_search					"╧юшёъ"
+#define MESSAGEHEAD_login					"┬їюф"
+#define MESSAGEHEAD_userlist				"╧юы№чютрЄхыш"
+#define MESSAGEHEAD_personalmsg				"╧ЁштрЄ"
+#define MESSAGEHEAD_makeannounce			"─юсртшЄ№ рэюэё"
+#define MESSAGEHEAD_favourites				"╚чсЁрээюх"
+#define MESSAGEHEAD_banlist				"┴рэышёЄ"
+
+#define MESSAGEMAIN_ban_save			"╤ярёшсю. ╤яшёюъ ёюїЁрэхэ єёях°эю."
+#define MESSAGEMAIN_ban_save2			"╫хЁхч эхёъюы№ъю ёхъєэф т√ тхЁэхЄхё№ ъ ёяшёъє ёююс∙хэшщ"
+
+#define MESSAGEMAIN_ban_no_save			"┬эшьрэшх! ╤яшёюъ эх ёюїЁрэхэ!"
+#define MESSAGEMAIN_ban_empty			"╬ЄяЁртыхээ√щ ёяшёюъ яєёЄ. "
+
+
+#define MESSAGEMAIN_add_banned			"╤ююс∙хэшх эх ьюцхЄ с√Є№ фюсртыхэю"
+#define MESSAGEMAIN_add_banned2 		"╬ЄяЁртър ёююс∙хэшщ ё тр°хую ъюья№■ЄхЁр с√ыр чряЁх∙хэр └фьшэшёЄЁрЄюЁюь"
+#define MESSAGEMAIN_add_closed			"╤ююс∙хэшх эх ьюцхЄ с√Є№ фюсртыхэю"
+#define MESSAGEMAIN_add_closed2 		"▌Єр тхЄт№ чръЁ√Єр └фьшэшёЄЁрЄюЁюь, эют√х ёююс∙хэш  эх яЁшэшьр■Єё "
+#define MESSAGEMAIN_add_invalid_reply	"╤ююс∙хэшх эх ьюцхЄ с√Є№ фюсртыхэю"
+#define MESSAGEMAIN_add_invalid_reply2	"╤ююс∙хэшх эр ъюЄюЁюх ┬√ їюЄшЄх юЄтхЄшЄ№ эх ёє∙хёЄтєхЄ!"
+
+#define MESSAGEMAIN_add_ok				"╤ююс∙хэшх фюсртыхэю"
+#define MESSAGEMAIN_add_ok_login		"╤ююс∙хэшх фюсртыхэю, ┬√ тю°ыш т ъюэЇхЁхэЎш■ "
+#define MESSAGEMAIN_add_ok2				"╤ярёшсю чр єўрёЄшх. "
+
+#define MESSAGEMAIN_add_spelling		"╤ююс∙хэшх эх ьюцхЄ с√Є№ фюсртыхэю "
+#define MESSAGEMAIN_add_spelling2		"┬р°х ёююс∙хэшх ёюфхЁцшЄ чряЁх∙хээ√х ёыютр, яюяЁюсєщЄх эряшёрЄ№ хую схч эшї"
+
+#define MESSAGEMAIN_add_no_name			"┬ тр°хь ёююс∙хэшш эхЄ шьхэш"
+#define MESSAGEMAIN_add_no_name2 		"╫Єюс√ юЄяЁртшЄ№ ёююс∙хэшх, ┬√ фюыцэ√ єърчрЄ№ яю ъЁрщэхщ ьхЁх ╥хьє ш тр°х ╚ь "
+
+#define MESSAGEMAIN_add_no_subject		"┬ тр°хь ёююс∙хэшш эхЄ Єхь√"
+#define MESSAGEMAIN_add_no_subject2 	"╫Єюс√ юЄяЁртшЄ№ ёююс∙хэшх, ┬√ фюыцэ√ єърчрЄ№ яю ъЁрщэхщ ьхЁх ╥хьє ш тр°х ╚ь "
+
+// TODO :.....
+#define MESSAGEMAIN_add_no_right_thrd	"╤ючфрэшх эютюую яюЄюър с√ыю чряЁх∙хэю трь ьюфхЁрЄюЁрьш"
+#define MESSAGEMAIN_add_no_right_thrd2	"┼ёыш ┬√ ёўшЄрхЄх, ўЄю ¤Єю ю°шсър ёт цшЄхё№ ё ьюфхЁрЄюЁрьш ЇюЁєьр"
+
+#define MESSAGEMAIN_add_emptymsg_java	"═ряш°шЄх, яюцрыєщёЄр, ўЄю-эшсєф№ ш єърцшЄх яю тючьюцэюёЄш Єюяшъ ┬р°хую ёююс∙хэш ! ╤ярёшсю!"
+#define MESSAGEMAIN_add_tolong_java		"╨рчьхЁ ┬р°хую ёююс∙хэш  яЁхт√°рхЄ ьръёшьєь эр"
+#define MESSAGEMAIN_add_tolong_java2	"ёшьтюыют! ╧юцрыєщёЄр, єьхэ№°шЄх хую, Ёрчсшт эр эхёъюы№ъю ўрёЄхщ! ╤ярёшсю!"
+
+#define MESSAGEMAIN_add_no_body			"┬ тр°хь ёююс∙хэшш эхЄ Єхыр"
+#define MESSAGEMAIN_add_no_body2 		"╫Єюс√ юЄяЁртшЄ№ ёююс∙хэшх, ┬√ фюыцэ√ эряшёрЄ№ Єхыю ёююс∙хэш "
+
+#define MESSAGEMAIN_add_flood			"┬√ я√ЄрхЄхё№ яютЄюЁэю юЄяЁртшЄ№ ёююс∙хэшх шыш тЁхь  ьхцфє тр°шьш ёююс∙хэш ьш ёыш°ъюь ьрыю"
+#define MESSAGEMAIN_add_flood2 			"┼ёыш т√ я√ЄрхЄхё№ юЄяЁртшЄ№ эютюх ёююс∙хэшх, яюяЁюсєщЄх ёфхырЄ№ ¤Єю ўхЁхч эхъюЄюЁюх тЁхь "
+
+#define MESSAGEMAIN_unknownerr			"╧Ёюшчю°ыр эхшчтхёЄэр  ю°шсър"
+#define MESSAGEMAIN_unknownerr2 		"╤ююс∙шЄх яюцрыєщёЄр └фьшэшёЄЁрЄюЁє юс ¤Єющ ю°шсъх"
+
+#define MESSAGEMAIN_requesterror 		"╬°шсюўэ√щ чряЁюё эр фхщёЄтшх"
+#define MESSAGEMAIN_requesterror2 		"┬√ шыш тр° сЁюєчхЁ яхЁхфрыш эхяЁртшы№эє■ ёё√ыъє, ш ёъЁшяЄ эх ьюцхЄ хх юсЁрсюЄрЄ№."
+
+#define MESSAGEMAIN_nonexistingmsg 		"▌Єю ёююс∙хэшх эх ёє∙хёЄтєхЄ шыш ттхфхэю эхяЁртшы№эю"
+#define MESSAGEMAIN_nonexistingmsg2 	"┬√ шыш тр° сЁюєчхЁ яхЁхфрыш эхяЁртшы№э√щ эюьхЁ ёююс∙хэш , яхЁхчруЁєчшЄх яюцрыєщёЄр ёЄЁрэшЎє шыш ттхфшЄх яЁртшы№э√щ эюьхЁ"
+
+#define MESSAGEMAIN_threadwasclosed		"╤юёЄю эшх ¤Єющ тхЄтш с√ыю єёях°эю шчьхэхэю"
+#define MESSAGEMAIN_threadwasclosed2	"┬хЄт№ ьюуыр ёЄрЄ№ чръЁ√Єющ шыш юЄъЁ√Єющ"
+
+#define MESSAGEMAIN_threadchangehided	"┬шфшьюёЄ№ ¤Єющ тхЄтш с√ыр єёях°эю шчьхэхэр"
+#define MESSAGEMAIN_threadchangehided2	"┬хЄт№ ьюуыр ёЄрЄ№ тшфшьющ шыш эхтшфшьющ"
+
+#define MESSAGEMAIN_threaddeleted		"┬хЄт№ с√ыр єёях°эю єфрыхэр"
+#define MESSAGEMAIN_threaddeleted2		""
+
+#define MESSAGEMAIN_threadrolled		"┬хЄт№ с√ыр єёях°эю ётхЁэєЄр шыш ЁрчтхЁэєЄр"
+#define MESSAGEMAIN_threadrolled2		""
+
+#define MESSAGEMAIN_messagechanged		"╤ююс∙хэшх с√ыю шчьхэхэю"
+#define MESSAGEMAIN_messagechanged2		"╤ярёшсю чр єўрёЄшх"
+
+#define MESSAGEMAIN_incorrectpwd 		"╙ърчрээюх шь  єцх ёє∙хёЄтєхЄ ш ттхфхэ эхтхЁэ√щ ярЁюы№"
+#define MESSAGEMAIN_incorrectpwd2 		"╧ЁютхЁ№Єх яЁртшы№эюёЄ№ эряшёрэш  ярЁюы  ш шьхэш<BR>┼ёыш ┬√ їюЄшЄх юЄяЁртшЄ№ ёююс∙хэшх эх ЁхухёЄЁшЁє ё№ т ъюэЇхЁхэЎшш яюяЁюсєщЄх єърчрЄ№ фЁєуюх эх чрэ Єюх шь "
+
+#define MESSAGEMAIN_robotmessage 		"╚ёяюы№чютрэшх єърчрээюую шьхэш чряЁх∙хэю"
+#define MESSAGEMAIN_robotmessage2 		""
+
+#define MESSAGEMAIN_session_end 		"┬√ я√ЄрхЄхё№ яюыєўшЄ№ фюёЄєя шёяюы№чє  эхртЄюЁшчшЁютрээюх яюфъы■ўхэшх"
+#define MESSAGEMAIN_session_end2 		"╤ъюЁхх тёхую тЁхь  тр°хую яюфъы■ўхэш  шёЄхъыю ш ┬√ фюыцэ√ ттхёЄш шь  ш ярЁюы№ чрэютю"
+
+#define MESSAGEMAIN_logoff_not_logged_in	"┬√ эх тю°ыш эю я√ЄрхЄхё№ т√щЄш"
+#define MESSAGEMAIN_logoff_not_logged_in2 	"┬√ єцх т√°ыш, ┬рь эх эєцэю фхырЄ№ ¤Єю х∙х Ёрч"
+
+#define MESSAGEMAIN_logoff_ok			"┬√ єёях°эю т√°ыш"
+#define MESSAGEMAIN_logoff_ok2 			""
+
+#define MESSAGEMAIN_login_ok			"%s, %s, ┬√ єёях°эю тю°ыш т ъюэЇхЁхэЎш■"
+#define MESSAGEMAIN_login_ok2			""
+
+#define MESSAGEMAIN_login_helloday		"─юсЁ√щ фхэ№"
+#define MESSAGEMAIN_login_helloevn		"─юсЁ√щ тхўхЁ"
+#define MESSAGEMAIN_login_hellonight	"─юсЁющ эюўш"
+#define MESSAGEMAIN_login_hellomor		"─юсЁюх єЄЁю"
+
+#define MESSAGEMAIN_lostpassw_ok		"┬р° ярЁюы№ с√ы юЄяЁртыхэ яю email"
+#define MESSAGEMAIN_lostpassw_ok2		"╤ярёшсю чр яюы№чютрэшх ёшёЄхьющ эряюьшэрэш  ярЁюы "
+
+#define MESSAGEMAIN_access_denied		"─юёЄєя ъ ¤Єющ ЇєэъЎшш фы  ┬рё чряЁх∙хэ"
+#define MESSAGEMAIN_access_denied2 		"╧ЁютхЁ№Єх, тю°ыш ыш т√ т ъюэЇхЁхэЎш■<BR>┼ёыш ┬√ ёўшЄрхЄх, ўЄю ¤Єю ю°шсър - юсЁрЄшЄхё№ ъ ьюфхЁрЄюЁрь ъюэЇхЁхэЎшш"
+
+#define MESSAGEMAIN_spamtry				"┴ыюъшЁютър яюя√Єъш ёярьр шыш чр∙шЄр юЄ яютЄюЁэющ юЄяЁртъш"
+#define MESSAGEMAIN_spamtry2 			"┼ёыш ┬√ я√ЄрхЄхё№ юЄяЁртшЄ№ ёююс∙хэшх, Єю ¤Єю чэрўшЄ, ўЄю юэю єцх юЄяЁртыхэю ш трь эхчрўхь фхырЄ№ ¤Єю х∙х Ёрч"
+
+#define MESSAGEMAIN_BANNED_REASON		"╧Ёшўшэр чряЁхЄр фюсртыхэш  ёююс∙хэшщ фы  ┬рё с√ыр :"
+
+#define MESSAGEMAIN_browser_return		"<P ALIGN=CENTER>┬р° сЁюєчхЁ фюыцхэ тхЁэєЄ№ трё ъ ёяшёъє ёююс∙хэшщ ўхЁхч эхёъюы№ъю ёхъєэф</P>"
+
+#define MESSAGEMAIN_browser_to_thread		"<P><P ALIGN=CENTER><B><A STYLE=\"text-decoration:underline;\" HREF=\"" MY_CGI_URL "?read=%d\">┬хЁэєЄ№ё </A> ъ ётюхьє ёююс∙хэш■</B></P></P><P></P>"
+
+#define MESSAGEMAIN_admin_contact 		"┼ёыш ┬√ ёўшЄрхЄх ўЄю ¤Єю эхяЁртшы№эю, юсЁрЄшЄхё№ ъ <A HREF=\"mailto:" ADMIN_MAIL "\">└фьшэшёЄЁрЄюЁє</A> ъюэЇхЁхэЎшш"
+
+/***************** ╘юЁьр юЄяЁртъш ёююс∙хэшщ ******************/
+#define	MESSAGEMAIN_post_newmessage 		"═ютюх ёююс∙хэшх"
+#define	MESSAGEMAIN_post_replymessage 		"╬ЄтхЄшЄ№"
+#define	MESSAGEMAIN_post_editmessage 		"╚чьхэшЄ№ ёююс∙хэшх"
+
+#define MESSAGEMAIN_post_you_name			"<b>╚ь :</b>"
+#define MESSAGEMAIN_post_your_password		"<b>╧рЁюы№:</b>"
+#define MESSAGEMAIN_post_login_me			"<b>└тЄюыюушэ</b>"
+#define MESSAGEMAIN_post_hostname			"<b>Host:</b>"
+#define MESSAGEMAIN_post_message_subject	"<b>╥хьр:</b>"
+#define MESSAGEMAIN_post_message_body 		"<b>╤ююс∙хэшх:</b> <FONT class=cl>(<A HREF=\"" MY_CGI_URL \
+	"?help\" STYLE=\"text-decoration:underline;\" target=_blank>╩ръ фюсртшЄ№ ЇюЁьрЄшЁютрэшх, ърЁЄшэъш, ш Є.ф. т тр°х ёююс∙хэшх</A>)</FONT>"
+
+#define MESSAGEMAIN_post_disable_wwwconf_tags	"╬Єъы■ўшЄ№ Ёрёяючэртрэшх ╥хуют ъюэЇхЁхэЎшш"
+#define MESSAGEMAIN_post_disable_smile_tags		"╬Єъы■ўшЄ№ Ёрёяючэртрэшх  ёьрщы-ъюфют"
+#define MESSAGEMAIN_post_reply_acknl 			"╧юыєўрЄ№ єтхфюьыхэш  юс юЄтхЄрї яю яюўЄх"
+
+#define MESSAGEMAIN_post_preview_message	"╧ЁхфтрЁшЄхы№э√щ яЁюёьюЄЁ"
+#define MESSAGEMAIN_post_post_message 		"╬ЄяЁртшЄ№"
+#define MESSAGEMAIN_post_edit_message		"╚чьхэшЄ№"
+
+/****************** ╨хушёЄЁрЎшюээр  ЇюЁьр ******************/
+#define MESSAGEMAIN_register_intro			"╨хушёЄЁрЎш "
+#define MESSAGEMAIN_register_chg_prof_intro "╚чьхэхэшх яЁюЇрщыр"
+#define MESSAGEMAIN_register_login			"╚ь  (*):"
+#define MESSAGEMAIN_register_displayname	"╬ЄюсЁрцрхьюх шь  :"
+#define MESSAGEMAIN_register_oldpass_req	"─ы  шчьхэхэш  яЁюЇрщыр ┬√ <U>фюыцэ√</U> єърчрЄ№ ┬р° ярЁюы№ !"
+#define MESSAGEMAIN_register_oldpassword	"╤ЄрЁ√щ ярЁюы№ (*):"
+#define MESSAGEMAIN_register_if_want_change	"┼ёыш т√ їюЄшЄх шчьхэшЄ№ ярЁюы№ ттхфшЄх ЄєЄ эют√щ ярЁюы№, шэрўх юёЄрт№Єх ¤Єш яюы  яєёЄ√ьш"
+#define MESSAGEMAIN_register_password1		"═ют√щ ярЁюы№ (*):"
+#define MESSAGEMAIN_register_password2		"═ют√щ ярЁюы№ х∙х Ёрч (*):"
+#define MESSAGEMAIN_register_full_name		"┬р°х яюыэюх шь :"
+#define MESSAGEMAIN_register_validemail_req	"┬√ фюыцэ√ єърчрЄ№ фхщёЄтє■∙шщ E-Mail рфЁхё <BR>(юэ сєфхЄ шёяюы№чютрЄ№ё  фы  яюыєўхэш  ярЁюы  ш ётюфюъ яю ъюэЇхЁхэЎшш)"
+#define MESSAGEMAIN_register_email			"E-Mail рфЁхё (*):"
+#define MESSAGEMAIN_register_email_pub		"╧єсышўэ√щ фюёЄєя ъ ┬р°хьє E-Mail"
+#define MESSAGEMAIN_register_homepage		"└фЁхё ┬р°хщ фюьр°эхщ ёЄЁрэшЎ√:"
+#define MESSAGEMAIN_register_icq			"ICQ :"
+#define MESSAGEMAIN_register_signature		"┼ёыш ┬√ їюЄшЄх ёюсёЄтхээє■ яюфяшё№ (сєфхЄ яю ты Є№ё  т" \
+		" эют√ї ёююс∙хэш ї яю єьюыўрэш■,<BR>ш эх ьюцхЄ с√Є№ фышээхх 255 ёшьтюыют), ттхфшЄх хх чфхё№," \
+		" шыш юёЄрт№Єх яюых яєёЄ√ь"
+#define MESSAGEMAIN_register_selectedusers	"┬√сЁрэ√х яюы№чютрЄхыш, ёююс∙хэш  ъюЄюЁ√ї сєфєЄ яюфётхўштрЄ№ё <BR>" \
+		"(ърцфюх шь  яш°хЄё  эр эютющ ёЄЁюъх, ьръёшьры№эю ьюцэю ттхёЄш 184 ёшьтюыр)"
+#define MESSAGEMAIN_register_about			"┬тхфшЄх ўЄю-эшсєф№ ю ┬р°шї шэЄхЁхёрї, їюссш ш Є.ф."
+#define MESSAGEMAIN_register_private_prof	"╧єсышўэ√щ фюёЄєя ъ ┬р°хьє яЁюЇрщыє"
+#define MESSAGEMAIN_register_always_emlackn	"┬ёхуфр юЄё√ырЄ№ юЄтхЄ√ эр ┬р°ш ёююс∙хэш  эр E-mail"
+#define MESSAGEMAIN_register_pmsg_disable	"╟ряЁхЄшЄ№ ёхЁтшё яЁштрЄэ√ї ёююс∙хэшщ"
+#define MESSAGEMAIN_register_pmsg_email		"╧Ёшё√ырЄ№ юяютх∙хэшх ю яЁшїюфх эютюую яЁштрЄэюую ёююс∙хэш  яю яюўЄх"
+#define MESSAGEMAIN_register_req_fields		"┬ёх яюы  юЄьхўхээ√х *  ты ■Єё  юс чрЄхы№э√ьш !"
+#define MESSAGEMAIN_register_register		"╟рЁхушёЄЁшЁютрЄ№"
+#define MESSAGEMAIN_register_edit			"╚чьхэшЄ№"
+#define MESSAGEMAIN_register_delete			"╙фрышЄ№"
+#define MESSAGEMAIN_register_confirm_delete	"яюфЄтхЁфшЄ№ єфрыхэшх"
+#define MESSAGEMAIN_register_view_saving    "╚ёяюы№чютрЄ№ яЁюЇрщы фы  їЁрэхэш  эрёЄЁюхъ тэх°эхую тшфр"
+	
+#define CONFIRM_DELETE_CHECKBOX_TEXT		"confirm_delete"
+
+/**************** ╨хушёЄЁрЎшюээ√х ёююс∙хэш  ***************/
+/**************** registration mnssages ***************/
+#define MESSAGEMAIN_register_create_ex		"╧ЁюЇшы№ ёючфрэ"
+#define MESSAGEMAIN_register_create_ex2		"ш ┬√ ртЄюьрЄшўхёъш тю°ыш"
+
+#define MESSAGEMAIN_register_edit_ex		"╧юы№чютрЄхы№ с√ы ёючфрэ / шчьхэхэ"
+#define MESSAGEMAIN_register_edit_ex2		""
+
+#define MESSAGEMAIN_register_edit_err		"╧Ёюшчю°ыр ю°шсър яЁш юсэютыхэшш яЁюЇрщыр"
+#define MESSAGEMAIN_register_edit_err2		"┬ючьюцэю, ёЄюшЄ яюяЁюсютрЄ№ х∙х Ёрч"
+
+#define MESSAGEMAIN_register_delete_ex		"╧юы№чютрЄхы№ єфрыхэ"
+#define MESSAGEMAIN_register_delete_ex2		""
+
+#define MESSAGEMAIN_register_delete_logoff	"┬р° ръърєэЄ с√ы єфрыхэ"
+#define MESSAGEMAIN_register_delete_logoff2	""
+
+#define MESSAGEMAIN_register_already_exit	"▌Єю шь  єцх чрэ Єю"
+#define MESSAGEMAIN_register_already_exit2	"╧юяЁюсєщЄх яЁшфєьрЄ№ фЁєуюх шь "
+
+#define MESSAGEMAIN_register_invalid_psw	"╚ь  шыш ярЁюы№ ттхфхэ√ эхяЁртшы№эю"
+#define MESSAGEMAIN_register_invalid_psw2	"┬√ фюыцэ√ ттхёЄш яЁртшы№эюх шь  ш ярЁюы№ шыш хёыш т√ шчьхэ хЄх" \
+											" шэЇюЁьрЎш■ ю ёхсх т√ фюыцэ√ яхЁхф ¤Єшь тющЄш т ёшёЄхьє"
+
+#define MESSAGEMAIN_register_invalid_n_psw	"╧юфЄтхЁцфхэшх ярЁюы  эх ёютярфрхЄ шыш ярЁюы№ ёыш°ъюь ъюЁюЄъшщ"
+#define MESSAGEMAIN_register_invalid_n_psw2	"─ы  яюфЄтхЁцфхэш  ярЁюы  трь эхюсїюфшью ттхёЄш хую тхЁэю" \
+											" фтрцф√ ш фышэр ярЁюы  фюыцэр с√Є№ эх ьхэхх 3 ёшьтюыют"
+
+#define MESSAGEMAIN_register_invalid_email	"┬тхфхээ√щ E-Mail рфЁхё эхъюЁЁхъЄхэ"
+#define MESSAGEMAIN_register_invalid_email2	"╫Єюс√ чрЁхушёЄЁшЁютрЄ№ё  т ъюэЇхЁхэЎшш ┬√ фюыцэ√ ттхёЄш фхщёЄтє■∙шщ" \
+											" E-Mail шэрўх ┬√ эх ёьюцхЄх яюы№чютрЄ№ё  эхъюЄюЁ√ьш ЇєэъЎш ьш ъюэЇхЁхэЎшш"
+
+#define MESSAGEMAIN_register_cannot_delete	"╧юы№чютрЄхы№ %s эх ьюцхЄ с√Є№ єфрыхэ"
+#define MESSAGEMAIN_register_cannot_delete2	"┬√ фюыцэ√ ттхёЄш яЁртшы№эюх шь  ш ярЁюы№"
+
+#define MESSAGEMAIN_register_invalid_lg_spell	"═хЄ Єръюую шьхэш яюы№чютрЄхы  шыш юэю эхяЁртшы№эюх"
+#define MESSAGEMAIN_register_invalid_lg_spell2	"┬√ фюыцэ√ ттхёЄш яЁртшы№эюх шь  ш ярЁюы№(фышэр шьхэш фюыцэр с√Є№ эх ьхэ№°х 3 ёшьтюыют)"
+
+
+/***************** profile information *****************/
+#define MESSAGEMAIN_profview_intro			"╚эЇюЁьрЎш  ю яюы№чютрЄхых: "
+#define MESSAGEMAIN_profview_login			"╚ь : "
+#define MESSAGEMAIN_profview_postpersmsg	"юЄяЁртшЄ№ яЁштрЄэюх ёююс∙хэшх"
+#define MESSAGEMAIN_profview_editinfo		"шчьхэшЄ№"
+#define MESSAGEMAIN_profview_altname		"└ы№ЄхЁэрЄштэюх шь : "
+#define MESSAGEMAIN_profview_fullname		"╧юыэюх шь : "
+#define MESSAGEMAIN_profview_homepage		"─юьр°э   ёЄЁрэшЎр: "
+#define MESSAGEMAIN_profview_email			"Email: "
+#define MESSAGEMAIN_profview_dogsubstitute	" at "
+#define MESSAGEMAIN_profview_user_icq		"ICQ: "
+#define MESSAGEMAIN_profview_user_status	"╤ЄрЄєё: "
+#define MESSAGEMAIN_profview_u_moderator	"<FONT COLOR=#FF0000>╠юфхЁрЄюЁ</FONT>"
+#define MESSAGEMAIN_profview_u_user			"╬с√ўэ√щ яюы№чютрЄхы№"
+#define MESSAGEMAIN_profview_postcount		"╫шёыю ёююс∙хэшщ: "
+#define MESSAGEMAIN_profview_reg_date		"─рЄр ЁхушёЄЁрЎшш: "
+#define MESSAGEMAIN_profview_login_date		"┬Ёхь  яюёыхфэхую фюёЄєяр: "
+#define MESSAGEMAIN_profview_about_user		"╬ яюы№чютрЄхых: "
+#define MESSAGEMAIN_profview_refreshcnt		"╫шёыю юсэютыхэшщ: "
+#define MESSAGEMAIN_profview_lastip			"╧юёыхфэшщ тїюф ё: "
+#define MESSAGEMAIN_profview_persmsgcnt		"┬ёхую яхЁёюэры№э√ї ёююс∙хэшщ(яЁюўшЄрэю): "
+
+#define MESSAGEMAIN_profview_no_user		"<P></P><CENTER>╧юы№чютрЄхы№ %s эх чрЁхушёЄЁшЁютрэ т ¤Єющ ъюэЇхЁхэЎшш</CENTER>"
+
+#define MESSAGEMAIN_profview_privacy_prof	"─ры№эхщ°р  шэЇюЁьрЎш  ю яюы№чютрЄхых эхфюёЄєяэр"
+#define MESSAGEMAIN_profview_privacy_inf	"╦шўэр  шэЇюЁьрЎш "
+
+#define MESSAGEMAIN_profview_sechdr			"╩юф схчюярёЄэюёЄш фы  Єхь√: "
+#define MESSAGEMAIN_profview_secbdy			"╩юф схчюярёЄэюёЄш фы  Єхыр: "
+
+//	user statuses
+#define USER_STATUS_COUNT 5
+extern char *UserStatus_List[USER_STATUS_COUNT];
+
+extern char *UserRight_List[USERRIGHT_COUNT];
+
+/******************* session information *******************/
+#define MESSAGEMAIN_session_intro		"╟рЁхушёЄЁшЁютрээ√х ёхёёшш "
+#define MESSAGEMAIN_session_ip			"IP рфЁхё тїюфр:"
+#define MESSAGEMAIN_session_date			"┬Ёхь  яюёыхфэхую фюёЄєяр:"
+#define MESSAGEMAIN_session_state			"╤юёЄю эшх ёхёёшш:"
+#define MESSAGEMAIN_session_state_active	"ръЄштэр "
+#define MESSAGEMAIN_session_state_toclose	"чръЁ√Є№"
+#define MESSAGEMAIN_session_state_closed	"чръЁ√Єр"
+#define MESSAGEMAIN_session_no			"эхЄ ёхёёшщ"
+#define MESSAGEMAIN_session_closed_ok		"╤хёёш  чръЁ√Єр<BR>"
+#define MESSAGEMAIN_session_closed_ok2	"╤ярёшсю чр єўрёЄшх!"
+#define MESSAGEMAIN_session_closed_no		"╤хёёш  эх чръЁ√Єр<BR>"
+#define MESSAGEMAIN_session_check_failed	"╤хёёш  эх эрщфхэр<BR>┬ючьюцэю, юэр с√ыр Єюы№ъю ўЄю чръЁ√Єр"
+#define MESSAGEMAIN_session_close_failed	"╬°шсър яЁш чръЁ√Єшш ёхёёшш<BR>"
+#define MESSAGEMAIN_session_ip_nocheck		"(схч яЁютхЁъш)"
+#define MESSAGEMAIN_session_ip_check		""
+
+/************* private(personal) messages **************/
+#define MESSAGEMAIN_privatemsg_send_message "╬ЄяЁртшЄ№ ёююс∙хэшх"
+#define MESSAGEMAIN_privatemsg_send_msg_btn "╬ЄяЁртшЄ№"
+#define MESSAGEMAIN_privatemsg_prev_msg_btn "╧ЁхфяЁюёьюЄЁ"
+#define MESSAGEMAIN_privatemsg_send_msg_hdr "╬ЄяЁртшЄ№ ышўэюх ёююс∙хэшх"
+#define MESSAGEMAIN_privatemsg_send_msg_usr	"╧юы№чютрЄхы■: "
+#define MESSAGEMAIN_privatemsg_send_msg_bdy "╤ююс∙хэшх (эх ьюцхЄ с√Є№ сюы№°х 384 ёшьтюыют)"
+
+#define MESSAGEMAIN_privatemsg_msgwassent	"╤ююс∙хэшх с√ыю юЄяЁртыхэю яюы№чютрЄхы■"
+#define MESSAGEMAIN_privatemsg_msgwassent2	"╤ярёшсю чр єўрёЄшх"
+
+#define MESSAGEMAIN_privatemsg_msgcantsend	"╤ююс∙хэшх эх ьюцхЄ с√Є№ юЄяЁртыхэю !"
+#define MESSAGEMAIN_privatemsg_msgcantsend2	"╧юяЁюсєщЄх яючцх !"
+
+#define MESSAGEMAIN_privatemsg_denyunreg	"─рээр  тючьюцэюёЄ№ эхфюёЄєяэр эхчрЁхушёЄЁшЁютрээ√ь яюы№чютрЄхы ь !<BR>"
+#define MESSAGEMAIN_privatemsg_denyunreg2	"─ы  Єюую ўЄюс шьхЄ№ тючьюцэюёЄ№ юЄяЁрты Є№ ш яюыєўрЄ№ яхЁёюэры№эюх ёююс∙хэшх ┬√ фюыцэ√ чрЁхушёЄЁшЁютрЄ№ё  т ъюэЇхЁхэЎшш !<BR><BR>"
+
+#define MESSAGEMAIN_privatemsg_invalid_user	"┬√ фюыцэ√ єърчрЄ№ ёє∙хёЄтє■∙шщ эшъ яюы№чютрЄхы "
+#define MESSAGEMAIN_privatemsg_invalid_body "╤ююс∙хэшх эх ьюцхЄ с√Є№ яєёЄюх (шэрўх ъръющ ёь√ёы хую яюё√ырЄ№ ?)"
+#define MESSAGEMAIN_privatemsg_tolong_body	"╤ююс∙хэшх ёыш°ъюь фышээюх, єьхэ№°шЄх хую фышэє"
+#define MESSAGEMAIN_privatemsg_disable_pmsg "╧юы№чютрЄхы№ чряЁхЄшы яюыєўхэшх яхЁёюэры№э√ї ёююс∙хэшщ,<BR>юЄяЁртшЄ№ хьє яхЁёюэры№эюх ёююс∙хэшх эхтючьюцэю"
+
+#define MESSAGEMAIN_privatemsg_header		"╧хЁёюэры№э√х ёююс∙хэш  фы  яюы№чютрЄхы "
+
+#define MESSAGEMAIN_privatemsg_disabled		"╧юыєўхэшх яхЁёюэры№э√ї ёюююс∙хэшщ чряЁх∙хэю!"
+
+#define MESSAGEMAIN_privatemsg_newmsgcnt	"╩юышўхёЄтю эют√ї ёююс∙хэшщ:"
+#define MESSAGEMAIN_privatemsg_nonewmsg		"═ют√ї ёююс∙хэшщ эхЄ"
+
+#define	MESSAGEMAIN_privatemsg_allmsgcnt	"╤ююс∙хэшщ тёхую, яюыєўхэю:"
+#define	MESSAGEMAIN_privatemsg_allmsgcnt1	"юЄяЁртыхэю:"
+
+#define MESSAGEMAIN_privatemsg_writenewmsg	"═ряшёрЄ№ эютюх яхЁёюэры№эюх ёююс∙хэшх"
+
+#define MESSAGEMAIN_privatemsg_newmsgann	"┼ёЄ№"
+#define MESSAGEMAIN_privatemsg_newmsgann1	"эхяЁюўшЄрээ√ї ышўэ√ї ёююс∙хэшщ фы  ┬рё!"
+
+#define MESSAGEMAIN_privatemsg_newmark		"<font color=red>[ ═ютюх !]</font>"
+
+#define MESSAGEMAIN_privatemsg_answer		"[╬ЄтхЄшЄ№]"
+
+#define MESSAGEMAIN_privatemsg_fromuser		"╬Є яюы№чютрЄхы :"
+#define MESSAGEMAIN_privatemsg_touser		"╧юы№чютрЄхы■:"
+#define MESSAGEMAIN_privatemsg_date			"╬ЄяЁртыхэю:"
+
+/***************** favourites system *****************/
+#define MESSAGEMAIN_favourites_denyunreg	"─рээр  тючьюцэюёЄ№ эхфюёЄєяэр эхчрЁхушёЄЁшЁютрээ√ь яюы№чютрЄхы ь !<BR>"
+#define MESSAGEMAIN_favourites_denyunreg2	"─ы  Єюую, ўЄюс√ шьхЄ№ тючьюцэюёЄ№ їЁрэшЄ№ ёё√ыъш эр шчсЁрээ√х ёююс∙хэш , ┬√ фюыцэ√ чрЁхушёЄЁшЁютрЄ№ё  ш тющЄш т ъюэЇхЁхэЎш■ !<BR><BR>"
+
+#define MESSAGEMAIN_favourites_listclear	"┬р° ёяшёюъ шчсЁрээюую яєёЄ"
+
+#if USER_FAVOURITES_SUPPORT == 1
+#define MESSAGEMAIN_favourites_added		"╤ююс∙хэшх чрэхёхэю т ╚чсЁрээюх!<BR>"
+#define MESSAGEMAIN_favourites_added2		"╤ярёшсю чр єўрёЄшх !<BR>╥хяхЁ№ ёё√ыъє эр ¤Єю ёююс∙хэшх ьюцэю эрщЄш т ёяшёъх<BR>"
+#define MESSAGEMAIN_favourites_addno		"╤ююс∙хэшх эх чрэхёхэю т ╚чсЁрээюх!<BR>"
+#define MESSAGEMAIN_favourites_addexist		"╤ююс∙хэшх єцх яЁшёєЄёЄтєхЄ т ёяшёъх!<BR>┬ючьюцэю, ┬√ Єюы№ъю ўЄю хую фюсртшыш ш я√ЄрхЄхё№ ёфхырЄ№ ¤Єю х∙х Ёрч<BR>"
+#define MESSAGEMAIN_favourites_addnoplace	"╙ ┬рё єцх ёюїЁрэхэю 20 ёююс∙хэшщ!<BR>─ы  Єюую, ўЄюс√ фюсртшЄ№ ¤Єю ёююс∙хэшх, эхюсїюфшью єфрышЄ№ їюЄ  с√ юфэю шч єцх ёюїЁрэхээ√ї<BR>"
+#define MESSAGEMAIN_favourites_deleted		"╤ююс∙хэшх єфрыхэю шч ╚чсЁрээюую!<BR>"
+#define MESSAGEMAIN_favourites_deleted2		"╤ярёшсю чр єўрёЄшх !<BR><BR>"
+#define MESSAGEMAIN_favourites_delno		"╤ююс∙хэшх эх єфрыхэю шч ╚чсЁрээюую!<BR>"
+#define MESSAGEMAIN_favourites_delnoexist	"╤ююс∙хэш  эхЄ т ёяшёъх !<BR> ┬ючьюцэю, ┬√ Єюы№ъю ўЄю хую єфрышыш<BR>"
+#else
+#define MESSAGEMAIN_favourites_added		"╧юЄюъ чрэхёхэ т ╚чсЁрээюх!<BR>"
+#define MESSAGEMAIN_favourites_added2		"╤ярёшсю чр єўрёЄшх !<BR>╥хяхЁ№ ёё√ыъє эр ¤ЄюЄ яюЄюъ ьюцэю эрщЄш т ёяшёъх<BR>"
+#define MESSAGEMAIN_favourites_addno		"╧юЄюъ эх чрэхёхэ т ╚чсЁрээюх!<BR>"
+#define MESSAGEMAIN_favourites_addexist		"╧юЄюъ єцх яЁшёєЄёЄтєхЄ т ёяшёъх!<BR>┬ючьюцэю, ┬√ Єюы№ъю ўЄю хую фюсртшыш<BR>"
+#define MESSAGEMAIN_favourites_addnoplace	"╙ ┬рё єцх ёюїЁрэхэю 20 яюЄюъют!<BR>─ы  Єюую, ўЄюс√ фюсртшЄ№ ¤ЄюЄ ЄЁхф, эхюсїюфшью єфрышЄ№ їюЄ  с√ юфшэ шч єцх ёюїЁрэхээ√ї<BR>"
+#define MESSAGEMAIN_favourites_deleted		"╧юЄюъ єфрыхэ шч ╚чсЁрээюую!<BR>"
+#define MESSAGEMAIN_favourites_deleted2		"╤ярёшсю чр єўрёЄшх !<BR><BR>"
+#define MESSAGEMAIN_favourites_delno		"╧юЄюъ эх єфрыхэ шч ╚чсЁрээюую!<BR>"
+#define MESSAGEMAIN_favourites_delnoexist	"╧юЄюър эхЄ т ёяшёъх !<BR> ┬ючьюцэю, ┬√ Єюы№ъю ўЄю хую єфрышыш<BR>"
+#define MESSAGEMAIN_favourites_addnoparent	"╤ююс∙хэшх эх  ты хЄё  яхЁт√ь фы  фрээюую яюЄюър!<BR>─юсрты Є№ ьюцэю Єюы№ъю яхЁт√х ёююс∙хэш  т ЄЁхфх"
+#endif
+
+/****************** global announces *****************/
+#define MESSAGEMAIN_globann_send_ann_hdr	"╨рчьхёЄшЄ№ эют√щ уыюсры№э√щ рэюэё"
+#define MESSAGEMAIN_globann_upd_ann_hdr		"╚чьхэшЄ№ уыюсры№э√щ рэюэё"
+#define MESSAGEMAIN_globann_send_ann_body	"╥хъёЄ рэюэёр (эх ьюцхЄ с√Є№ сюы№°х 512 ёшьтюыют)"
+#define MESSAGEMAIN_globann_upd_ann_id		"╬сэютшЄ№ эюьхЁ рэюэёр (ёэютр тёяы√тхЄ)"
+#define MESSAGEMAIN_globann_send_ann_btn	"╬ЄяЁртшЄ№"
+#define MESSAGEMAIN_globann_prev_ann_btn	"╧ЁхфяЁюёьюЄЁ"
+
+#define MESSAGEMAIN_globann_preview_hdr		"╧ЁхфтрЁшЄхы№э√щ яЁюёьюЄЁ рэюэёр"
+
+#define MESSAGEMAIN_globann_anncantsend		"└эюэё эх ьюцхЄ с√Є№ фюсртыхэ !"
+#define MESSAGEMAIN_globann_anncantsend2	"╠юцхЄ с√Є№ ┬рь ёЄюшЄ яюяЁюсютрЄ№ яючцх..."
+
+#define MESSAGEMAIN_globann_annwassent		"└эюэё с√ы фюсртыхэ"
+#define MESSAGEMAIN_globann_annwassent2		"╤ярёшсю чр єўрёЄшх"
+
+#define MESSAGEMAIN_globann_annwasupdated	"└эюэё с√ы юсэютыхэ"
+#define MESSAGEMAIN_globann_annwasupdated2	"╤ярёшсю чр єўрёЄшх"
+
+#define MESSAGEMAIN_globann_tolong			"└эюэё ёыш°ъюь фышээ√щ, єьхэ№°шЄх хую ш яютЄюЁшЄх яюя√Єъє"
+#define MESSAGEMAIN_globann_toshort			"└эюэё ёыш°ъюь ъюЁюЄъшщ, чрўхь хую тююс∙х яшёрЄ№ ;) ?"
+
+#define MESSAGEMAIN_globann_wasdeleted		"└эюэё с√ы єёях°эю єфрыхэ"
+#define MESSAGEMAIN_globann_wasdeleted2		"<BR>"
+
+#define MESSAGEMAIN_globann_cannotdel		"└эюэё эх ьюцхЄ с√Є№ єфрыхэ!"
+#define MESSAGEMAIN_globann_cannotdel2		"┬ючьюцэю, є ┬рё эхфюёЄрЄюўэю яЁрт фы  єфрыхэш "
+
+#define MESSAGEMAIN_globann_invalidnum		"╙ърчрэ эх ёє∙хёЄтє■∙шщ шфхэЄшЇшърЄюЁ рэюэёр!"
+#define MESSAGEMAIN_globann_invalidnum2		"╧ЁютхЁ№Єх ш юсэютшЄх ёё√ыъє яю ъюЄюЁющ ┬√ яюярыш ё■фр"
+
+#define MESSAGEMAIN_globann_delannounce		"╙фрышЄ№ ¤ЄюЄ рэюэё"
+#define MESSAGEMAIN_globann_updannounce		"╬сэютшЄ№ ¤ЄюЄ рэюэё"
+#define MESSAGEMAIN_globann_postedby		"╬ЄяЁртыхэ"
+
+#define MESSAGEMAIN_globann_showall			"╧юърчрЄ№ тёх ръЄштэ√х рэюэё√"
+#define MESSAGEMAIN_globann_hidenewann		"╤ъЁ√Є№ Єхъє∙шх рэюэё√"
+
+/******************  moderation form  ******************/
+#define MESSAGEMAIN_moderate_hide_thread 	"╤ъЁ√Є№ ¤Єє тхЄт№"
+#define MESSAGEMAIN_moderate_close_thread	"╟ръЁ√Є№ ¤Єє тхЄт№"
+#define MESSAGEMAIN_moderate_unhide_thread 	"╧юърчрЄ№ ¤Єє тхЄт№"
+#define MESSAGEMAIN_moderate_unclose_thread	"╬ЄъЁ√Є№ ¤Єє тхЄт№"
+#define MESSAGEMAIN_moderate_delete_thread	"╙фрышЄ№ ¤Єє тхЄт№"
+#define MESSAGEMAIN_moderate_change_message	"╚чьхэшЄ№ ¤Єю ёююс∙хэшх"
+#define MESSAGEMAIN_moderate_roll			"╤тхЁэєЄ№ ¤Єє тхЄт№"
+#define MESSAGEMAIN_moderate_unroll			"╨рчтхЁэєЄ№ ¤Єє тхЄт№"
+
+/********************* ╘юЁьр тїюфр *********************/
+#define MESSAGEMAIN_login_login_header	"┬тхфшЄх ┬р°х шь  ш ярЁюы№"
+#define MESSAGEMAIN_login_loginname		" ╚ь  : "
+#define MESSAGEMAIN_login_password		" ╧рЁюы№ : "
+#define	MESSAGEMAIN_login_ipcheckshort		"═х яЁютхЁ Є№ IP"
+#define MESSAGEMAIN_login_ipcheck		"═х яЁютхЁ Є№ IP рфЁхё фы  ёхёёшш"
+
+#define MESSAGEMAIN_login_lostpassw		"<CENTER>┼ёыш ┬√ чрс√ыш ┬р° ярЁюы№ <A HREF=\"" MY_CGI_URL "?login=lostpasswform\">ъышъэшЄх ЄєЄ</A></CENTER><BR><BR>"
+
+/**************** ╘юЁьр "чрс√ыш ярЁюы№" ****************/
+#define MESSAGEMAIN_lostpassw_header	"<BIG>╤шёЄхьр эряюьшэрэш  ярЁюы </BIG><BR><BR>┬тхфшЄх ┬р° эшъ ш рфЁхё ¤ыхъЄЁюээющ яюўЄ√<BR>" \
+										"ш ┬√ яюыєўшЄх яшё№ью ё тр°шь ярЁюыхь"
+#define MESSAGEMAIN_lostpassw_hretry	"<BOLD><FONT COLOR=RED>┬√ єърчрыш эхтхЁэ√щ эшъ ш/шыш рфЁхё ¤ыхъЄЁюээющ яюўЄ√</FONT></BOLD><BR>" \
+										"╧юцрыєщёЄр, яЁютхЁ№Єх ┬р° эшъ ш email ш яютЄюЁшЄх яюя√Єъє х∙х Ёрч"
+#define MESSAGEMAIN_lostpassw_loginname	" ═шъ : "
+#define MESSAGEMAIN_lostpassw_email		" Email : "
+#define MESSAGEMAIN_lostpassw_getpassw	"╧юыєўшЄ№ ярЁюы№"
+
+/******************    search form   ******************/
+#define MESSAGEMAIN_search_searchmsg	"╚ёърЄ№ ёююс∙хэш "
+
+#define MESSAGEMAIN_search_howtouse		"┬тхфхэшх т яЁртшыр шёяюы№чютрэш  яюшёър.<BR>╧юшёъ тхфхЄё  яю <U><B>ўрёЄшўэ√ь</B></U> ъєёърь ёыют <B>(эх ьхэ№°х ЄЁхї ёшьтюыют!)</B> ёюфхЁцр∙шьё  т " \
+										"<U>Єхых</U> шыш <U>чруюыютъх</U> ёююс∙хэш .<BR>╤ыютр т ёЄЁюъх яюшёър ьюцэю Ёрчфхы Є№ яЁюсхырьш, ўЄю чэрўшЄ шёърЄ№" \
+										" ёююс∙хэш  ёюфхЁцр∙шх тёх Єръшх яюфёЄЁюъш.<BR>═р фрээюь ёхЁтхЁх яюшёъ ьюцхЄ чрэ Є№ юЄ 1 фю 10 ёхъєэф " \
+										"(т чртшёшьюёЄш юЄ чруЁєцхээюёЄш), яю¤Єюьє, ЁхъюьхэфєхЄё  фюцфрЄ№ё  Ёхчєы№ЄрЄют яюшёър, р эх эрцшьрЄ№ \"╧юшёъ\" " \
+										"х∙х Ёрч."
+#define MESSAGEMAIN_search_lastindexed	"╧юёыхфэхх яЁюшэфхъёшЁютрэюх ёююс∙хэшх"
+#define MESSAGEMAIN_search_notindexed	"╚эфхъёрЎш  эх т√яюыэхэр"
+#define MESSAGEMAIN_search_indexerror	"╬°шсър шэфхъёют"
+#define MESSAGEMAIN_search_containing	"ёюфхЁцр∙шх"
+#define MESSAGEMAIN_search_sentby		"яюёырээ√х"
+#define MESSAGEMAIN_search_search_str	"╤ЄЁюър чряЁюёр : "
+#define MESSAGEMAIN_search_result1		"╨хчєы№ЄрЄ яюшёър: "
+#define MESSAGEMAIN_search_result2		"ёютярфхэшщ эрщфхэю <EM>(┴єфхЄ яюърчрэю 100 эр ёЄЁрэшЎє)</EM>"
+#define MESSAGEMAIN_search_result_nothing	"═шўхую эх эрщфхэю, яюяЁюсєщЄх шчьхэшЄ№ ъы■ўхт√х ёыютр яюшёър"
+#define MESSAGEMAIN_search_result_pages		"╤ЄЁрэшЎ√ Ёхчєы№ЄрЄют:"
+
+/******************* message view form ******************/
+#define MESSAGEMAIN_viewthread_sent		"╤ююс∙хэшх с√ыю яюёырэю:"
+#define MESSAGEMAIN_viewthread_ipview	", IP: "
+#define MESSAGEMAIN_viewthread_date		"─рЄр:"
+#define MESSAGEMAIN_viewthread_mdate	"╚чьхэхэ:"
+#define MESSAGEMAIN_viewthread_sigdisabled	"<U><I><SMALL>╧юы№чютрЄхы№ шьххЄ яюфяшё№, эю юЄюсЁрцхэшх яюфяшёхщ чряЁх∙хэю т эрёЄЁющърї.</SMALL></I></U>"
+#define	MESSAGEMAIN_in_this_thread		"<CENTER><BIG>╤ююс∙хэш  т ¤Єюь яюЄюъх</BIG></CENTER>"
+
+/********************** userlist ***********************/
+#define MESSAGEMAIN_total_user_count		"┬ёхую яюы№чютрЄхыхщ: "
+#define MESSAGEMAIN_userlist_sortby			"╤юЁЄшЁютрЄ№ яю: "
+#define MESSAGEMAIN_userlist_sortbyname		"эшъє"
+#define MESSAGEMAIN_userlist_sortbydate		"фрЄх яюёыхфэхую фюёЄєяр"
+#define MESSAGEMAIN_userlist_sortbypcnt		"ъюы-тє ёююс∙хэшщ"
+#define MESSAGEMAIN_userlist_sortbyhost		"їюёЄє/IP рфЁхёє"
+#define MESSAGEMAIN_userlist_sortbyrefresh	"яю ъюышўхёЄтє юсэютыхэшщ"
+#define MESSAGEMAIN_userlist_sortbyright	"яю яЁртрь яюы№чютрЄхыхщ"
+
+/******************  configure form   ******************/
+#define MESSAGEHEAD_to_message				"╧хЁхщЄш ъ юЄтхЄрь"
+#define MESSAGEHEAD_configure_showmsgs		"╧юърчрЄ№ тхЄтш"
+#define MESSAGEHEAD_configure_msgslast		" яюёырээ√х т Єхўхэшх яюёыхфэшї "
+#define MESSAGEHEAD_configure_lastnum		" яюёыхфэшї "
+#define MESSAGEHEAD_configure_lastnum2		" тхЄтхщ "
+#define MESSAGEHEAD_configure_showstyle		"╤Єшы№ юЄюсЁрцхэш  : "
+#define MESSAGEHEAD_configure_disablesmiles "├ыюсры№эю юЄьхэшЄ№ ёьрщы-ъюф√"
+#define MESSAGEHEAD_configure_disableuppic	"╬Єъы■ўшЄ№ чруюыютюъ ъюэЇхЁхэЎшш"
+#define MESSAGEHEAD_configure_disable2links	"╬Єъы■ўшЄ№ тЄюЁє■ ёЄЁюъє ёё√ыюъ"
+#define MESSAGEHEAD_configure_ownpostshighlight	"╬Єъы■ўшЄ№ т√фхыхэшх ёюсёЄтхээ√ї ёююс∙хэшщ"
+#define MESSAGEHEAD_configure_showhostnames	"╬Єъы■ўшЄ№ юЄюсЁрцхэшх їюёЄют т шэфхъёх"
+#define MESSAGEHEAD_configure_showaltnames	"╬Єъы■ўшЄ№ юЄюсЁрцхэшх ры№ЄхЁэрЄштэ√ї шьхэ"
+#define MESSAGEHEAD_configure_showsign		"╬Єъы■ўшЄ№ юЄюсЁрцхэшх яюфяшёхщ яюы№чютрЄхыхщ"
+#define MESSAGEHEAD_configure_plus_is_href	"\" " TAG_NEW_MSG_MARK "\"  ты хЄё  ёё√ыъющ эр ёыхфє■∙хх эютюх ёююс∙хэшх"
+#define MESSAGEHEAD_configure_showreplyform	"═х юЄюсЁрцрЄ№ ЇюЁьє юЄтхЄр"
+#define MESSAGEHEAD_configure_applysettings	"╤юїЁрэшЄ№ эрёЄЁющъш"
+
+
+#define MESSAGEHEAD_configure_saving_to_profile "═рёЄЁющъш ёюїЁрэ ■Єё  т яЁюЇрщых ш сєфєЄ фюёЄєяэ√ ё ы■сюую сЁрєчхЁр"
+#define MESSAGEHEAD_configure_saving_to_browser "═рёЄЁющъш ёюїЁрэ ■Єё  т сЁрєчхЁх ш фюёЄєяэ√ Єюы№ъю ё фрээюую ъюья№■ЄхЁр"
+#define MESSAGEHEAD_configure_view_saving    "╚чьхэшЄ№ ёяюёюс їЁрэхэш  эрёЄЁюхъ ьюцэю эр <a href=\""MY_CGI_URL"?register=form\" style=\"text-decoration:underline;\"  >ёЄЁрэшЎх ЁхфръЄшЁютрэш  яЁюЇрщыр</a>"
+
+// coded as "1"
+//#define MESSAGEHEAD_configure_showhronforward	"╧ю яюЄюърь т їЁюэюыюушўхёъюь тшфх, яю тючЁрёЄрэш■"
+// coded as "2"
+#define MESSAGEHEAD_configure_showhronbackward		"╧ю яюЄюърь т їЁюэюыюушўхёъюь тшфх, яю єс√трэш■"
+// coded as "3"
+#define MESSAGEHEAD_configure_showhronwothreads		"╧ю ёююс∙хэш ь т їЁюэюыюушўхёъюь тшфх, яю тючЁрёЄрэш■"
+// coded as "4"
+#define MESSAGEHEAD_configure_showhrononlyheaders	"╧ю ёююс∙хэш ь т їЁюэюыюушўхёъюь тшфх, Єюы№ъю чруюыютъш"
+
+
+#define WWWCONF_FULL_NAME "╘юЁєь"
+
+// for STABLE_TITLE = 1
+#if STABLE_TITLE == 1
+#define TITLE_StaticTitle 		"not used " VERSION
+#endif
+
+/******************* topic support *********************/
+#if TOPICS_SYSTEM_SUPPORT
+#define TOPICS_COUNT	18
+#define TOPICS_DEFAULT_SELECTED	0
+// this variable should be defined in main.cpp
+extern char *Topics_List[TOPICS_COUNT];
+extern int Topics_List_map[TOPICS_COUNT];
+#endif
+
+/**************************** title messages *****************************/
+// for STABLE_TITLE = 0
+// board name prefix
+#define TITLE_WWWConfBegining		"╘юЁєь"
+#define TITLE_divider				" : "
+// forms name
+#define TITLE_WWWConfIndex			" "
+#define TITLE_Form					"═ютюх ёююс∙хэшх"
+#define TITLE_WriteReply			"═ряшёрЄ№ юЄтхЄ"
+#define TITLE_Configure				"═рёЄЁющър"
+#define TITLE_Error					"╬°шсър !"
+#define TITLE_Spamtry				"┴ыюъшЁютрэр яюя√Єър ёярьр!"
+#define TITLE_Login					"┬їюф т ъюэЇхЁхэЎш■"
+#define TITLE_Logoff				"┬√їюф шч ъюэЇхЁхэЎшш"
+#define TITLE_LostPassword			"╟рс√ыш ярЁюы№?"
+#define TITLE_PasswordSent			"╧рЁюы№ юЄяЁртыхэ"
+#define TITLE_IncorrectPassword		"═хяЁртшы№э√щ ярЁюы№!"
+#define TITLE_ClosingMessage		"╟ръЁ√Є№ ёююс∙хэш "
+#define TITLE_HidingMessage			"╤ъЁ√Є№ ёююс∙хэш "
+#define TITLE_DeletingMessage		"╙фрышЄ№ ёююс∙хэш "
+#define TITLE_ChangingMessage		"╚чьхэшЄ№ ёююс∙хэшх - "
+#define TITLE_RollMessage			"╨рчтхЁэєЄ№ ёююс∙хэшх"
+#define TITLE_HelpPage				"╤яЁртър"
+#define TITLE_Registration			"╨хушёЄЁрЎш  / шчьхэшЄ№ яЁюЇшы№"
+#define TITLE_Search				"╧юшёъ ёююс∙хэшщ"
+#define TITLE_ProfileInfo			"╚эЇюЁьрЎш  ю яюы№чютрЄхых"
+#define TITLE_UserList				"╤яшёюъ ■чхЁют"
+#define TITLE_PrivateMsg			"╧ЁштрЄэ√х ёююс∙хэш "
+#define TITLE_AddPrivateMsg			"═ряшёрЄ№ яЁштрЄэюх ёююс∙хэш "
+#define TITLE_PrivateMsgWasPosted	"╧ЁштрЄэюх ёююс∙хэшх юЄяЁртыхэю"
+#define TITLE_PostGlobalAnnounce	"─юсртшЄ№ уыюсры№э√щ рэюэё"
+#define TITLE_GlobalAnnWasPosed		"├ыюсры№э√щ рэюэё фюсртыхэ"
+#define TITLE_GlobalAnnWasDeleted	"├ыюсры№э√щ рэюэё єфрыхэ"
+#define TITLE_FavouritesPage		"╚чсЁрээюх"
+#define TITLE_FavouritesPageAdd		"─юсртыхэшх Єхь√ т ╚чсЁрээюх"
+#define TITLE_FavouritesPageDel		"╙фрыхэшх Єхь√ шч ╚чсЁрээюую"
+#define TITLE_BanSave		"╤юїЁрэхэшх ёяшёър чрсрэхээ√ї рщяш"
+#define TITLE_ClSession		        "╟ръЁ√Єшх ёхёёшш"
+
+/***************************** welcome messages **************************/
+#define WELCOME_CONFERENCE_HEADER	"<B>┬їюф:</B> "//"<U><B>┬ёхыхэёъюх ╟╦╬:</B></U> "	// :))) // namek ponyat :)
+//#define ZLO ""
+
+#define MESSAGEMAIN_ACTIVITY_STATVIEW	"└ъЄштэюёЄ№: <B><FONT COLOR=BLUE>%ld</FONT> <FONT COLOR=#229911>%ld</FONT></B>" \
+										" чр яюёыхфэшх 10 ьшэєЄ"
+#define MESSAGEMAIN_WELCOME_LOGGEDSTART	"<table class=cl><tr><td><font class=cl> " \
+										WELCOME_CONFERENCE_HEADER MESSAGEMAIN_WELCOME_HELLOREG "<FONT COLOR=BLUE>%s</FONT>%s<BR>%s%s</td>" \
+										"<td align=right class=cl>%s<BR>" MESSAGEMAIN_WELCOME_SELECTTOPIC " %s</font></td></tr></table>"
+
+#define MESSAGEMAIN_WELCOME_START	"<table class=cl><tr><td>"\
+		"<form method=post action=\""MY_CGI_URL "?login=action\">"\
+		"<font class=cl> " WELCOME_CONFERENCE_HEADER MESSAGEMAIN_login_loginname \
+		"<INPUT TYPE=TEXT NAME=\"mname\" class=cl SIZE=15 " \
+		"MAXLENGTH=%d VALUE=\"%s\">&nbsp;&nbsp;&nbsp;" MESSAGEMAIN_login_password \
+		"<INPUT TYPE=PASSWORD NAME=\"mpswd\" SIZE=15 class=cl MAXLENGTH=%d>&nbsp;&nbsp;&nbsp;"\
+		"<INPUT TYPE=CHECKBOX NAME=\"ipoff\" class=cl VALUE=1>" MESSAGEMAIN_login_ipcheckshort \
+		"&nbsp;&nbsp;&nbsp;<INPUT TYPE=SUBMIT class=cl VALUE=\"Enter\"></font><BR>%s%s</td>" \
+		"<td align=right class=cl>%s<BR>"  MESSAGEMAIN_WELCOME_SELECTTOPIC " %s</font></td></tr></table>"
+
+#define MESSAGEMAIN_WELCOME_HELLOREG		"┬√ тю°ыш т ъюэЇхЁхэЎш■ ъръ "
+#define MESSAGEMAIN_WELCOME_SELECTTOPIC		"┬√схЁшЄх Єхьє:"
+
+#define MESSAGEMAIN_WELCOME_NEWTHREADS_TEXT		"эют√ї яюЄюъют(ёююс∙хэшщ): %ld(%ld) шч %ld"
+#define MESSAGEMAIN_WELCOME_NEWTHREADS "<span id=\"new_count\">"\
+				MESSAGEMAIN_WELCOME_NEWTHREADS_TEXT"</span>"
+				
+#define MESSAGEMAIN_WELCOME_NONEWTHREADS_TEXT	"эют√ї ёююс∙хэшщ эхЄ, тёхую %ld"
+#define MESSAGEMAIN_WELCOME_NONEWTHREADS "<span id=\"new_count\">"\
+			MESSAGEMAIN_WELCOME_NONEWTHREADS_TEXT"</span>"
+
+			
+#define MESSAGEMAIN_WELCOME_NEWCOUNT_SCRIPT_NEW "<script>update_counter('new_count','"MESSAGEMAIN_WELCOME_NEWTHREADS_TEXT"');</script>"
+#define MESSAGEMAIN_WELCOME_NEWCOUNT_SCRIPT_NO_NEW "<script>update_counter('new_count','"MESSAGEMAIN_WELCOME_NONEWTHREADS_TEXT"');</script>"
+
+#define MESSAGEMAIN_WELCOME_NEWCOUNT_SCRIPT "<script>"\
+			"function update_counter(id, value){"\
+			"if (document.getElementById){"\
+				"el = document.getElementById(id);"\
+				"if(document.all) el.innerHTML = value;"\
+				"else{"\
+					"rng = document.createRange();"\
+					"rng.setStartBefore(el);"\
+					"htmlFrag = rng.createContextualFragment(value);"\
+					"while (el.hasChildNodes()) el.removeChild(el.lastChild);"\
+					"el.appendChild(htmlFrag);"\
+			"}}}</script>"
+			
+	
+
+#define MESSAGEMAIN_WELCOME_DISPLAYTIME		", яюърчрэ√ ёююс∙хэш  чр %d %s"
+#define MESSAGEMAIN_WELCOME_DISPLAYTHREADS	", яюърчрэ√ яюёыхфэшх %d яюЄюъют"
+
+#define MESSAGEMAIN_WELCOME_YOURSETTINGS	"тр°ш Єхъє∙шх Єхь√"
+#define MESSAGEMAIN_WELCOME_ALLTOPICS		"тёх Єхь√"
+
+/**************************** date/time messages *************************/
+#define MESSAGEMAIN_DATETIME_JAN			"▀этрЁ№"
+#define MESSAGEMAIN_DATETIME_FEB			"╘хтЁры№"
+#define MESSAGEMAIN_DATETIME_MAR			"╠рЁЄ"
+#define MESSAGEMAIN_DATETIME_APR			"└яЁхы№"
+#define MESSAGEMAIN_DATETIME_MAY			"╠рщ"
+#define MESSAGEMAIN_DATETIME_JUN			"╚■э№"
+#define MESSAGEMAIN_DATETIME_JUL			"╚■ы№"
+#define MESSAGEMAIN_DATETIME_AUG			"└туєёЄ"
+#define MESSAGEMAIN_DATETIME_SEP			"╤хэЄ сЁ№"
+#define MESSAGEMAIN_DATETIME_OCT			"╬ъЄ сЁ№"
+#define MESSAGEMAIN_DATETIME_NOV			"═ю сЁ№"
+#define MESSAGEMAIN_DATETIME_DEC			"─хърсЁ№"
+
+#define MESSAGEMAIN_DATETIME_DAY_SUN		"┬юёъЁхёхэ№х"
+#define MESSAGEMAIN_DATETIME_DAY_MON		"╧юэхфхы№эшъ"
+#define MESSAGEMAIN_DATETIME_DAY_TEU		"┬ЄюЁэшъ"
+#define MESSAGEMAIN_DATETIME_DAY_WED		"╤Ёхфр"
+#define MESSAGEMAIN_DATETIME_DAY_THU		"╫хЄтхЁу"
+#define MESSAGEMAIN_DATETIME_DAY_FRI		"╧ ЄэшЎр"
+#define MESSAGEMAIN_DATETIME_DAY_SAT		"╤єссюЄр"
+
+/**************************** mailing messeges ***************************/
+
+#define MAILACKN_HEADER "Content-type: text/html; charset=\"windows-1251\"\r\n\r\n"
+
+
+#define MAIL_SEND_GREETING	"<HTML>╟фЁртёЄтєщЄх, <bold><font color=#009000>"\
+		"<strong>%s</strong></font></bold>.<br />"
+		
+#define MAIL_SEND_SIGNING	"▌Єю яшё№ью яюёырэю ртЄюьрЄшўхёъш ЇюЁєьюь "WWWCONF_FULL_NAME \
+		".<br />┬рь <b>эх</b> ёыхфєхЄ юЄтхўрЄ№ эр эхую.<br /></HTML>"
+
+//	reply notification
+#define MAILACKN_REPLY_SUBJECT			WWWCONF_FULL_NAME ": %s"
+#define MAILACKN_REPLY_BODY		MAIL_SEND_GREETING \
+"%s юЄтхЄшы эр тр°х ёююс∙хэшх <strong>%s</strong>.<br /><br />"\
+"╥хьр юЄтхЄр:<strong> %s</strong><br />"\
+"----------- ╤ююс∙хэшх ---------<br />%s<br />-------------------------------<br /><br />"\
+"┬хё№ ЄЁхф ьюцэю єтшфхЄ№ <a href=\"" MA_READURL "?read=%d\">чфхё№</A><br /><br />"
+
+//	password recovery
+#define MAILACKN_LOSTPASS_SUBJECT  	WWWCONF_FULL_NAME ": ярЁюы№ фы  яЁюЇшы  %s"
+#define MAILACKN_LOSTPASS_BODY	MAIL_SEND_GREETING \
+"╥хъє∙шщ ярЁюы№ фы  тр°хую яЁюЇшы : %s<br /><br /><br />"
+
+
+//	private message
+#define MAILACKN_PRIVATEMSG_SUBJECT	WWWCONF_FULL_NAME ": эютюх ышўэюх ёююс∙хэшх юЄ %s"
+#define MAILACKN_PRIVATEMSG_BODY	MAIL_SEND_GREETING \
+"─ы  ┬рё яюыєўхэю эютюх ышўэюх ёююс∙хэшх юЄ <strong>%s</strong>.<br /><br />"\
+"----------- ╤ююс∙хэшх ---------<br />%s<br />-------------------------------<br /><br />"\
+"╬ЄтхЄшЄ№ эр эхую ьюцэю <a href=\"" MA_READURL "?persmsgform=%s\">чфхё№</a><br />" \
+"╧юёьюЄЁхЄ№ юёЄры№э√х ышўэ√х ёююс∙хэш  ┬√ ьюцхЄх <a href=\"" MA_READURL "?persmsg\">чфхё№</A><br /><br />"
+
+
+
+/**************************** mailing messeges ***************************/
+/*#define MAILACKN_SUBJECT			WWWCONF_FULL_NAME ": %s"
+#define MAILACKN_MAINBODY_FORMAT	"Content-type: text/html; charset=\"windows-1251\"\n<HTML>" \
+"╟фЁртёЄтєщЄх, <BOLD><FONT COLOR=#009000><STRONG>%s</STRONG></FONT></BOLD>.<BR> %s юЄтхЄшы эр тр°х ёююс∙хэшх <STRONG>%s</STRONG>." \
+"<BR><BR>╥хьр юЄтхЄр:<STRONG> %s</STRONG>\n<BR>----------- ╤ююс∙хэшх ---------<BR>%s<BR>-------------------------------" \
+"<BR><BR>┬хё№ ЄЁхф ьюцэю єтшфхЄ№ <A HREF=" WC_EMAILACN_READURL "?read=%d>чфхё№</A>" \
+"<BR><BR>This mail was generated automatically by mailing engine" \
+" of " WWWCONF_FULL_NAME ".<BR>You <B>SHOULD NOT REPLY</B> to this message.<BR></HTML>"
+*/
+//	password recovery
+/*#define MAILLOSTPASSW_SUBJECT		WWWCONF_FULL_NAME ": ярЁюы№ фы  яЁюЇшы  %s"
+#define MAILLOSTPASSW_MAINBODY_FORMAT	"Content-type: text/html; charset=\"windows-1251\"\n<HTML>" \
+"╟фЁртёЄтєщЄх, <BOLD><FONT COLOR=#009000><STRONG>%s</STRONG></FONT></BOLD>.<BR>╥хъє∙шщ ярЁюы№ фы  тр°хую яЁюЇшы : %s<BR>" \
+"<BR><BR>This mail was generated automatically by mailing engine" \
+" of " WWWCONF_FULL_NAME ".<BR>You <B>SHOULD NOT REPLY</B> to this message.<BR></HTML>"
+
+#define MAILACKN_PRIVATEMSG_SUBJECT			WWWCONF_FULL_NAME ": эютюх ышўэюх ёююс∙хэшх юЄ %s"
+#define MAILACKN_PRIVATEMSG_MAINBODY_FORMAT	"Content-type: text/html; charset=\"windows-1251\"\n<HTML>" \
+"╟фЁртёЄтєщЄх, <BOLD><FONT COLOR=#009000><STRONG>%s</STRONG></FONT></BOLD>.<BR> фы  ┬рё яюыєўхэю эютюх ышўэюх ёююс∙хэшх юЄ <STRONG>%s</STRONG>." \
+"<BR><BR>----------- ╤ююс∙хэшх ---------<BR>%s<BR>-------------------------------" \
+"<BR><BR>╬ЄтхЄшЄ№ эр эхую ьюцэю <A HREF=" WC_EMAILACN_READURL "?persmsgform=%s>чфхё№</A><BR>" \
+"╧юёьюЄЁхЄ№ юёЄры№э√х ышўэ√х ёююс∙хэш  ┬√ ьюцхЄх <A HREF=" WC_EMAILACN_READURL "?persmsg>чфхё№</A>" \
+"<BR><BR>This mail was generated automatically by mailing engine" \
+" of " WWWCONF_FULL_NAME ".<BR>You <B>SHOULD NOT REPLY</B> to this message.<BR></HTML>"
+*/
+
+/**************************** log messages *******************************/
+#define LOG_SPAM_TRY				"Spam try from %s:, deal=%s"
+#define LOG_UNKNOWN_URL				"Unknown URL request from : %s, deal=%s"
+#define LOG_UNHANDLED				"UNHANDLED EXCEPTION at %s at line %d from : %s\n\tError: %s\t\tQUERY_STRING=%s"
+#define LOG_UNHANDLED_HTML			"UNHANDLED EXCEPTION at %s at line %d from : %s<BR><table width=100%% cellpadding=1 cellspacing=1 border=1 bgcolor=#E1E1E1><TR><TD>%s</TD><TD>QUERY_STRING=%s</TD></TR></TABLE>"
+#define LOG_ERRORTYPEUNKN			"Unknown"
+#define LOG_ACCESS_DENIED			"Access denied from : %s, deal=%s"
+#define LOG_PSWDERROR				"Incorrect password from : %s, deal=%s"
+#define LOG_FATAL_NOMEMORY			"Unable to allocate memory block of size %d"
+#define LOG_FILESIZETOOHIGH			"Size of file %s is too high to be handled by this version"
+#define LOG_GETFILESIZEFAILED		"Filesize() failed for file %s"
+#define LOG_UNABLETOLOCATEFILE		"Unable to open/access file %s for R"
+#define LOG_UNABLETOLOCATEFILERW	"Unable to open/access file %s for RW"
+#define LOG_UNABLETOCREATEFILE		"Unable to open/create file %s"
+#define LOG_WARN_UNABLETOOPENFILE	"WARNING: Unable to open/access file %s, feature connected to this file will not be used"
+
+// from design.h
+/*=====================================================================*/
+#define TAG_MSG_HAVE_NO_BODY	" <FONT COLOR=BLACK>(-)</FONT>"
+#define TAG_MSG_HAVE_PIC		" (pic)"
+#define TAG_MSG_HAVE_URL		" (url)"
+#define TAG_MSG_CLOSED_THREAD	"<EM><SMALL><font color=#900000>(чръЁ√Єю) </font></EM></SMALL>"
+#define TAG_MSG_ROLLED_THREAD	"<EM><font color=#900000>CтхЁэєЄю: </font></EM>"
+#define TAG_ONLYHEADERS_POSTCNT "%s%s<EM>(юЄтхЄют: <b>%d</b>)</EM>%s"
+#define TAG_ONLYHEADERS_POSTCNT_MARKNEW	"%s%s<EM>(юЄтхЄют: <b>%d</b>, эют√ї: <b>%d</b>," \
+								" яюёыхфэшщ юЄтхЄ: <A STYLE=\"text-decoration:underline;\" " \
+								"HREF=%s?read=%ld>юЄ %s, %s</A>)</EM>%s"
+#define TAG_REPLY_PREFIX		"Re: "
+#define TAG_IP_NOT_DETECTED		"X.X.X.X"
+#define BAD_WORD_SYMBOL			'#'
+#define TAG_NEW_MSG_MARK_HREF	"<A NAME=\"n%d\" HREF=\"#n%d\"><EM class=e>+ </EM></A>"
+#define TAG_NEW_MSG_MARK		"<EM class=e>+ </EM>"
+
+/*********************** Topics **************************/
+#define DESIGN_TOPIC_TAG_OPEN		"["
+#define DESIGN_TOPIC_TAG_CLOSE		"]"
+#define DESIGN_TOPIC_DIVIDER		" &nbsp;"
+
+/***************** nick name information *****************/
+#define DESIGN_REGISTRED_NICK		"<b>%s</b>"
+#define DESIGN_REGISTRED_OWN_NICK	"<b><font color=red>%s</font></b>"
+#define DESIGN_SELECTEDUSER_NICK	"<b><font color=#FF9900>%s</font></b>"
+#define DESIGN_UNREGISTRED_NICK		"<b>%s</b>"
+
+/********************** favorites ************************/
+#define DESIGN_FAVORITES_DEL_THREAD "<FONT COLOR=RED SIZE=3>[X]</FONT>"
+#define DESIGN_FAVORITES_ADD_THREAD "<FONT COLOR=GREEN SIZE=3>[+]</FONT>"
+
+#define DESIGN_THREADS_DIVIDER_IMG	""
+#define DESIGN_THREADS_DIVIDER_HR	"\n<HR size=1>"
+#define DESIGN_THREADS_DIVIDER_grey	"#E9E9E9"
+extern char DESIGN_threads_divider[500];
+
+#define DESIGN_OP_DL				"<DL><DD>"
+#define DESIGN_CL_DL				"</DL>"
+#define DESIGN_OP_DIV				"<DIV>"
+#define DESIGN_OP_DIV_grey			"<DIV class=g>"
+#define DESIGN_OP_DIV_white			"<DIV class=w>"
+#define DESIGN_CL_DIV				"</DIV>"
+extern char DESIGN_open_dl[10];
+extern char DESIGN_open_dl_grey[20];
+extern char DESIGN_open_dl_white[20];
+extern char DESIGN_close_dl[10];
+
+#define DESIGN_BR		"<BR>"
+#define DESIGN_DD		"<DD>"
+extern char DESIGN_break[10];
+
+#define DESIGN_BUTTONS_DIVIDER			"&nbsp;&nbsp;"
+
+#define DESIGN_GLOBAL_BOARD_MESSAGE		"<P ALIGN=CENTER><BIG><STRONG>%s</STRONG></BIG><BR><BR>%s"
+
+#define DESIGN_VIEW_THREAD_BODY			"<br /><div class=\"body\">%s</div>"
+#define DESIGN_VIEW_THREAD_SIGN			"<br /><div class=\"sign\">%s</div>"
+#define DESIGN_VIEW_THREAD_MSG_HEADER	"<BR><DIV ALIGN=CENTER>"
+// meesage was sent by NIK
+#define DESIGN_VIEW_THREAD_MSG_SENT		"<BR>%s %s "
+#define DESIGN_VIEW_THREAD_MSG_SENT1	"&lt;<A HREF=\"mailto:%s\">%s</A>&gt; "
+#define DESIGN_VIEW_THREAD_MSG_SENT2	"<small>(%s)</small>"
+#define DESIGN_VIEW_THREAD_MSG_SENT3	"</DIV><BR>"
+// topic when reading 
+#define DESIGN_VIEW_THREAD_TOPIC		"<BIG>[%s]</BIG>&nbsp;&nbsp;"
+//date
+#define DESIGN_VIEW_THREAD_DATE			"<BR>%s %s"
+#define DESIGN_VIEW_THREAD_MDATE		"<I>(%s %s)</I>"
+
+#define DESIGN_INDEX_WELCOME_STRING		"<P ALIGN=CENTER> %s <big>%s</big>!"
+#define DESIGN_INDEX_WELCOME_STRING1	"  %s %ld %s, тёхую %d"
+#define DESIGN_INDEX_WELCOME_CLOSE		"</P>"
+
+#define DESIGN_POST_NEW_MESSAGE_TABLE	"<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3>"
+
+#define DESIGN_PREVIEW_PREVIEWMESSAGE	"<P ALIGN=CENTER><STRONG>%s</STRONG>"
+#define DESIGN_PREVIEW_CHANGEMESSAGE	"<P ALIGN=CENTER><STRONG>%s</STRONG>"
+
+#define DESIGN_BAN_REASON_STYLE			"<P ALIGN=CENTER> %s <BOLD><EM>%s</EM></BOLD>"
+
+#define DESIGN_MODERATOR_ENTER_HEADER	"<P ALIGN=CENTER>%s"
+
+#define DESIGN_LOSTPASSW_HEADER			"<P ALIGN=CENTER>%s"
+
+#define DESIGN_SEARCH_SEARCH_STR_WAS	"<BR><CENTER><EM>%s</EM>%s</CENTER>"
+#define DESIGN_SEARCH_RESULT			"<BR><CENTER>%s%ld %s</CENTER><BR>"
+#define DESIGN_SEARCH_NO_RESULT			"<BR><CENTER><B>%s %s</B></CENTER><BR>"
+
+#define DESIGN_COMMAND_TABLE_BEGIN	"<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=1 BGCOLOR=#dfdfdf width=100%%><TR><TD class=cs align=center>"
+#define DESIGN_COMMAND_TABLE_END	" ]</TD></TR></TABLE></CENTER>\n"
+
+#define DESIGN_BEGIN_LOGIN_OPEN			"<CENTER><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3>"
+#define DESIGN_END_LOGIN_CLOSE			"</TABLE></CENTER>"
+
+#define DESIGN_BEGIN_LOSTPASSW_OPEN		"<CENTER><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3>"
+#define DESIGN_END_LOSTPASSW_CLOSE		"</TABLE></CENTER>"
+
+#define DESIGN_BEGIN_REGISTER_OPEN		"<CENTER><TABLE BORDER=0 CELLSPACING=1 CELLPADDING=3>"
+#define DESIGN_END_REGISTER_CLOSE		"</TABLE></CENTER>"
+// nick in read_message
+#define DESIGN_MESSAGE_UNREG			"<b>%s</b><SMALL> (unreg)</SMALL>"
+
+#define DESIGN_BEGIN_USERINFO_INTRO_OPEN	"<CENTER><TABLE BORDER=0 CELLSPACING=1 CELLPADDING=3>"
+#define DESIGN_END_USERINFO_INTRO_CLOSE		"</TABLE></CENTER>"
+
+#define DESIGN_SEARCH_RESULT			"<BR><CENTER>%s%ld %s</CENTER><BR>"
+
+/******************* private messages *******************/
+#define DESIGN_PRIVATEMSG_FRAME				"%s <TABLE WIDTH=95%% BORDER=1 CELLSPACING=0 CELLPADDING=6 BGCOLOR=%s>" \
+											"<TR><TD ALIGN=LEFT> %s </TD></TR></TABLE> %s%s"
+#define DESIGN_PRIVATEMSG_FRAME_BGCL_IN		"#FFBBBB"
+#define DESIGN_PRIVATEMSG_FRAME_BGCL_OUT	"#BBBBFF"
+
+/********************** announces ***********************/
+#define DESIGN_GLOBALANN_FRAME		"%s <TABLE WIDTH=96%% BORDER=1 CELLSPACING=0 CELLPADDING=4 BGCOLOR=#DDDDDD>" \
+									"<TR><TD ALIGN=LEFT style=\"border-style:solid;border-width:1px;" \
+									"border-color:#AAAAAA;\" class=cl> %s<BR>%s" \
+									" %s (%s) %s</TD></TR></TABLE> %s"
+
+#define DESIGN_CONFIGURE_CHECKALL "Check/Uncheck All <input type=checkbox checked onClick=\"javascript:selectall(checked)\">" \
+"\n<script language=\"JavaScript\">\n" \
+"function selectall(state){\n" \
+"			var item,i=0;\n" \
+"			while (1) {\n" \
+"				item=eval(\"document.configure.topic\"+i);\n" \
+"				if (item) {	item.checked = state;i++;\n" \
+"				} else { break;	}\n" \
+"			}\n" \
+"}" \
+"</script>\n"
+
+#define DESIGN_WELCOME_QUICKNAV		"<SELECT CLASS=CL onchange=\"if (this.options[this.selectedIndex].value == '') this.selectedIndex=0;" \
+"else window.open(this.options[this.selectedIndex].value,'_top')\"><OPTION VALUE=\"" MY_CGI_URL "?index=0\"%s>%s</OPTION>" \
+"<OPTION VALUE=\"" MY_CGI_URL "?index=all\"%s>%s</OPTION>"
+
+
+/************************* ban list *************************/
+#define DESIGN_BAN_FORM	"<center><form action=\""MY_CGI_URL"?banlist=save\" method=\"post\">"\
+					"<textarea name=\"ban_list\" rows=\"30\" cols=\"70\" wrap=\"soft\">"
+
+#define DESIGN_BAN_FORM2	"</textarea><br /><input type=\"submit\" name=\"submit\" value=\"Save\">"\
+					"</form></center>"
+
+//****************************************************//
+#define HTML_START "<html><head>"
+
+#define TEXT_ENCODING_HEADER	"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1251\"><link rel=\"shortcut icon\" href=\"favicon.ico\"><meta http-equiv=\"Page-Exit\" content=\"progid:DXImageTransform.Microsoft.Fade(Duration=0.2)\">"
+
+#define TEXT_TOPBANNER_HEADER ""
+
+#define TEXT_STYLE_HEADER "<style>"\
+"body { background-color: #f0f0f0; color: #000000; margin: 0;padding:0;border: 0; }"\
+"A {text-decoration: none;}\nA:visited {color: #000088;}\n" \
+"table.cl {width: 100%%;background-color: #E1E1E1; padding: 8px; border: 0; margin:0; } "\
+"TD.under {font-size: 7pt;font-weight: bold;vertical-align: top;}\n" \
+".underhref {font-size: 7pt;}\n"\
+"BIG {font-size: 14pt;font-weight: bold;}\n" \
+"/* name */ NOBR B {font-size: 12pt;color: #207025;}\n"\
+"/* ip,counter */ EM {font-size: 9pt;font-style: normal;}\n"\
+"/* + for new */ A EM.e, EM.e {color: #cc0000;font-weight: bold;font-size: 13pt;}\n" \
+".cl, .cs {font-family: Verdana, Arial; font-size: 8pt}\n" \
+"div {padding: 1px 0 1px 25px;}\n"\
+"div.g, div.w {border-top: 1px solid #ccc; padding: 5px 0 2px 10px;padding-left: 10px}"\
+"div.g {background-color:" DESIGN_THREADS_DIVIDER_grey ";}\n" \
+"DD DL{margin-left:-15px;}\n" \
+"</style></head><body>\n" \
+"<a name=\"up\"></a>" 
+
+#define TEXT_TOPBANNER_MAP "<map name=\"bottom_map\">" \
+"<area shape=\"rect\" coords=\"669,11,700,39\" href=\"#up\" alt=\"═ртхЁї\">" \
+"<area shape=\"rect\" coords=\"700,11,732,39\" href=\"mailto:estet@pisem.net\" alt=\"Webmaster\">" \
+"</map>" \
+"<center><img src=\"files/top_image.gif\" usemap=\"#top_map\" border=\"0\" height=\"104\" width=\"750\"><br>" \
+"<!-- END Header -->" 
+
+#define TEXT_BOTTOMBANNER "\n<!-- Footer -->\n" \
+"<center><img src=\"files/bottom_image.gif\" usemap=\"#bottom_map\" border=\"0\" height=\"55\" width=\"750\"><br>" \
+"<table border=\"0\" width=\"750\"><tbody>" \
+"<tr><td class=\"under\" align=\"left\"></td>" \
+"<td class=\"under\" align=\"right\"></td></tr>" \
+"</tbody></table></center>" \
+"<!-- END Footer -->\n" \
+"</body></html>\n"
+
+#define TEXT_BOTTOMBANNER_SHORT "" /* "<P></P><CENTER><SMALL>╩юэЇхЁхэЎш  юёэютрэр эр фтшцъх " \
+"<A STYLE=\"text-decoration:underline;\" href=\"http://2ka.mipt.ru/~www/\" TARGET=\"_blank\">WWWConf " VERSION \
+"</A>, яюффхЁцштрхЄё  ш ьюфхЁшЁєхЄё  уЁєяяющ <a STYLE=\"text-decoration:underline;\" " \
+	"href=\"http://board.rt.mipt.ru/authors.html\">¤эЄєчшрёЄют</a>.</SMALL></CENTER></BODY></HTML>"*/
+
+#endif
blob - /dev/null
blob + b29b801f46fe170fccd8959e37e4f994fd3a5be6 (mode 644)
--- /dev/null
+++ src/profiles.cpp
@@ -0,0 +1,1114 @@
+/***************************************************************************
+                          profiles.h  -  profiles support
+                             -------------------
+    begin                : Wed Mar 14 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "hashindex.h"
+#include "profiles.h"
+#include "freedb.h"
+#include "error.h"
+
+/* return 1 if valid, 0 otherwise
+ */
+int isLoginStrValid(register char *s)
+{
+	while(*s != 0) {
+		if(((unsigned char)(*s)) < 32) {
+			return 0;
+		}
+		s++;
+	}
+	if(strlen(s) > PROFILES_MAX_USERNAME_LENGTH - 1) return 0;
+	return 1;
+}
+
+/* constructor */
+CProfiles::CProfiles()
+{
+	errnum = PROFILE_RETURN_ALLOK;
+}
+
+
+/* constructor */
+CProfiles::~CProfiles()
+{
+}
+
+/* write SProfile_FullUserInfo structure, allocating space for it automatically
+ * return 1 if successfull, otherwise zero 
+ */
+int CProfiles::WriteFullInfo(DWORD *idx, SProfile_FullUserInfo *FI)
+{
+	/* prepare about string length */
+	if(FI->AboutUser != NULL)
+		FI->size = (DWORD)strlen(FI->AboutUser);
+	else
+		FI->size = 0;
+
+	/* alloc free space */
+	CFreeDBFile fdf(F_PROF_FREEBODY, PROFILE_WASTED_FINFO_SIZE);
+	if(fdf.errnum != FREEDBFILE_ERROR_ALLOK)
+		return 0;
+
+	if((*idx = fdf.AllocFreeSpace(sizeof(SProfile_FullUserInfo) - sizeof(char*) +
+		FI->size)) == 0xFFFFFFFF) {
+		if(fdf.errnum != FREEDBFILE_ERROR_ALLOK) 
+			return 0;
+		
+		if(wcfseek(Fp_b, 0, SEEK_END) != 0)
+			return 0;
+		*idx = wcftell(Fp_b);
+	}
+	else {
+		if(wcfseek(Fp_b, *idx, SEEK_SET) != 0)
+			return 0;
+	}
+
+	/* write SProfile_FullUserInfo */
+	if(!fCheckedWrite(FI, sizeof(SProfile_FullUserInfo) - sizeof(char*), Fp_b))
+		return 0;
+	if(!fCheckedWrite(FI->AboutUser, FI->size, Fp_b))
+		return 0;
+
+	return 1;
+}
+/* read SProfile_FullUserInfo structure 
+ * return 1 if successfull, otherwise zero 
+ */
+int CProfiles::ReadFullInfo(DWORD idx, SProfile_FullUserInfo *FI)
+{
+	// read SProfile_FullUserInfo
+	if(wcfseek(Fp_b, idx, SEEK_SET) != 0)
+		return 0;
+	if(!fCheckedRead(FI, sizeof(SProfile_FullUserInfo) - sizeof(char*), Fp_b))
+		return 0;
+	
+	// prepare "about" string length
+	FI->AboutUser = (char*)malloc(FI->size + 1);
+
+	if(!fCheckedRead(FI->AboutUser, FI->size, Fp_b)) {
+		free(FI->AboutUser);
+		return 0;
+	}
+	// set final zero at the end of string
+	FI->AboutUser[FI->size] = 0;
+
+	return 1;
+}
+/* delete SProfile_FullUserInfo structure from profile body database
+ * by index [idx] and mark space as free
+ * return 1 if successfull, otherwise zero 
+ */
+int CProfiles::DeleteFullInfo(DWORD idx)
+{
+	/* read old Full Info */
+	SProfile_FullUserInfo *ofi = (SProfile_FullUserInfo*)malloc(sizeof(SProfile_FullUserInfo));
+
+	if(ReadFullInfo(idx, ofi) == 0) {
+		free(ofi);
+		return 0;
+	}
+
+	/* mark free space */
+	CFreeDBFile fdf(F_PROF_FREEBODY, PROFILE_WASTED_FINFO_SIZE);
+	if(fdf.errnum != FREEDBFILE_ERROR_ALLOK) {
+		free(ofi->AboutUser);
+		free(ofi);
+		return 0;
+	}
+	DWORD rr = sizeof(SProfile_FullUserInfo) - sizeof(char*) + ofi->size;
+	free(ofi->AboutUser);
+	free(ofi);
+	if(fdf.MarkFreeSpace(idx, rr) != FREEDBFILE_ERROR_ALLOK)
+		return 0;
+
+	return 1;
+}
+
+
+/* read count structures SProfile_UserInfo at index idx */
+int CProfiles::ReadUInfo(DWORD idx, SProfile_UserInfo *FI)
+{
+	if(wcfseek(Fp_i, idx, SEEK_SET) != 0)
+		return 0;
+	if(!fCheckedRead(FI, sizeof(SProfile_UserInfo), Fp_i))
+		return 0;
+
+	return 1;
+}
+
+/* write new info structure SProfile_UserInfo and return it index in *idx
+ * and seek to the find place 
+ * DESTROY curent position of Fp_i file !!!
+ * return 1 if successfull, otherwise zero returned
+ */
+int CProfiles::GetSpaceforUInfo(DWORD *idx)
+{
+	/* alloc free space */
+	CFreeDBFile fdf(F_PROF_FREENIDX, 0);
+	if(fdf.errnum != FREEDBFILE_ERROR_ALLOK)
+		return 0;
+
+	if((*idx = fdf.AllocFreeSpace(sizeof(SProfile_UserInfo))) == 0xFFFFFFFF) {
+		if(fdf.errnum != FREEDBFILE_ERROR_ALLOK)
+			return 0;
+		
+		if(wcfseek(Fp_i, 0, SEEK_END) != 0)
+			return 0;
+		*idx = wcftell(Fp_i);
+	}
+	else {
+		if(wcfseek(Fp_i, *idx, SEEK_SET) != 0)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* write count structures SProfile_UserInfo at index idx */
+int CProfiles::WriteUInfo(DWORD idx, SProfile_UserInfo *FI)
+{
+	if(wcfseek(Fp_i, idx, SEEK_SET) != 0)
+		return 0;
+	if(!fCheckedWrite(FI, sizeof(SProfile_UserInfo), Fp_i))
+		return 0;
+
+	return 1;
+}
+
+int CProfiles::DeleteUInfo(DWORD idx)
+{
+	/* mark free space */
+	CFreeDBFile fdf(F_PROF_FREENIDX, sizeof(SProfile_UserInfo));
+	if(fdf.errnum != FREEDBFILE_ERROR_ALLOK)	
+		return 0;
+	if(fdf.MarkFreeSpace(idx, sizeof(SProfile_UserInfo)) != FREEDBFILE_ERROR_ALLOK)
+		return 0;
+
+	return 1;
+}
+
+
+/* add new user to profile database
+ * return PROFILE_RETURN_ALLOK if successfull, otherwise standart error codes 
+ */
+int CProfiles::AddNewUser(SProfile_UserInfo *newprf, SProfile_FullUserInfo *FullUI, DWORD *ui_index)
+{
+	int ret, i;
+	DWORD idx;
+	DWORD rr;
+	DWORD ucount;
+	Fp_i = NULL;
+	Fp_b = NULL;
+
+	if(!isLoginStrValid(newprf->username) || strlen(newprf->username) < 3) {
+		return PROFILE_RETURN_INVALID_LOGIN;
+	}
+
+	if((ret = GetIndexOfString(newprf->username, &rr)) == HASHINDEX_ER_NOT_FOUND ||
+		ret == HASHINDEX_ER_IO_READ) {
+		/* prepare SProfile_UserInfo and sb structures */
+		newprf->postcount = 0;
+		FullUI->CreateDate = time(NULL);
+		newprf->LoginDate = 0;
+		newprf->persmsg = 0xffffffff;
+		newprf->persmescnt = 0;
+		newprf->readpersmescnt = 0;
+		newprf->postedmescnt = 0;
+		newprf->postedpersmsg = 0xffffffff;
+		newprf->RefreshCount = 0;
+
+
+		newprf->vs.dsm = CONFIGURE_SETTING_DEFAULT_dsm;
+		newprf->vs.topics = CONFIGURE_SETTING_DEFAULT_topics;
+		newprf->vs.tv = CONFIGURE_SETTING_DEFAULT_tv;
+		newprf->vs.tc = CONFIGURE_SETTING_DEFAULT_tc;
+		newprf->vs.ss = CONFIGURE_SETTING_DEFAULT_ss;
+		newprf->vs.lsel = CONFIGURE_SETTING_DEFAULT_lsel;
+		newprf->vs.tt = CONFIGURE_SETTING_DEFAULT_tt;
+		newprf->vs.tz = DATETIME_DEFAULT_TIMEZONE;
+		
+		// New status = 0
+		newprf->Status = 0;
+		for( i=0; i<PROFILES_FAV_THREADS_COUNT; i++)
+			newprf->favs[i]=0;
+			
+		/* create new index */
+		if((Fp_i = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+			goto Unlock_and_return;
+		if((Fp_b = wcfopen(F_PROF_BODY, FILE_ACCESS_MODES_RW)) == NULL)
+			goto Unlock_and_return;
+		
+		/********* lock Fp_i, Fp_b files *********/
+		lock_file(Fp_i);
+		lock_file(Fp_b);
+		
+		// read unique user ID
+		if(!fCheckedRead(&(newprf->UniqID), sizeof(newprf->UniqID), Fp_i))
+			goto Unlock_and_return;
+		(newprf->UniqID)++;
+		
+		// read user count
+		if(!fCheckedRead(&ucount, sizeof(ucount), Fp_i))
+			goto Unlock_and_return;
+		// increment user count
+		ucount++;
+		
+		// get free index for user info structure
+		if(GetSpaceforUInfo(&idx) == 0)
+			goto Unlock_and_return;
+		
+		if(ui_index != NULL) *ui_index = idx;
+
+		if(wcfseek(Fp_i, idx, SEEK_SET) != 0)
+			goto Unlock_and_return;
+
+		// write SProfile_FullUserInfo
+		if(WriteFullInfo(&(newprf->FullInfo_ID), FullUI) == 0) {
+			goto Unlock_and_return;
+		}
+
+		// write SProfile_UserInfo
+		if(WriteUInfo(idx, newprf) == 0) {
+			goto Unlock_and_return;
+		}
+
+		if(AddStringToHashedIndex(newprf->username, idx) != HASHINDEX_ER_OK) {
+			DeleteUInfo(idx);
+			DeleteFullInfo(newprf->FullInfo_ID);
+			goto Unlock_and_return;
+		}
+
+		// write new unique user ID and current user count
+		if(wcfseek(Fp_i, 0, SEEK_SET) != 0)
+			goto Unlock_and_return;
+		if(!fCheckedWrite(&(newprf->UniqID), sizeof(newprf->UniqID), Fp_i))
+			goto Unlock_and_return;
+		if(!fCheckedWrite(&ucount, sizeof(ucount), Fp_i))
+			goto Unlock_and_return;
+		
+		unlock_file(Fp_i);
+		unlock_file(Fp_b);
+		/********* unlock Fp_i, Fp_b files *********/
+		
+		wcfclose(Fp_i);
+		wcfclose(Fp_b);
+		return PROFILE_RETURN_ALLOK;
+		
+Unlock_and_return:
+		// error - unlock and exit
+		if(Fp_i) {
+			unlock_file(Fp_i);
+			wcfclose(Fp_i);
+		}
+		if(Fp_b) {
+			unlock_file(Fp_b);
+			wcfclose(Fp_b);
+		}
+		return PROFILE_RETURN_DB_ERROR;
+	}
+
+	return PROFILE_RETURN_ALREADY_EXIST;
+}
+
+/* delete user [name] from profile database
+ * return PROFILE_RETURN_ALLOK if successfull, otherwise standart error codes 
+ */
+int CProfiles::DeleteUser(char *name)
+{
+	DWORD ret, idx, ucount;
+	SProfile_UserInfo *pi;
+	Fp_i = NULL;
+	Fp_b = NULL;
+
+	ret = GetIndexOfString(name, &idx);
+
+	switch(ret) {
+	case HASHINDEX_ER_NOT_FOUND:
+		return PROFILE_RETURN_INVALID_LOGIN;
+
+	case HASHINDEX_ER_OK:
+		pi = (SProfile_UserInfo*)malloc(sizeof(SProfile_UserInfo));
+
+		// index exist - try to read block
+		if((Fp_i = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+			goto Do_Exit;
+
+		if((Fp_b = wcfopen(F_PROF_BODY, FILE_ACCESS_MODES_RW)) == NULL)
+			goto Do_Exit;
+
+		/********* lock Fp_i, Fp_b *********/
+		lock_file(Fp_i);
+		lock_file(Fp_b);
+
+		if(wcfseek(Fp_i, idx, SEEK_SET) != 0)
+			goto Do_Exit;
+
+		if(!fCheckedRead(pi, sizeof(SProfile_UserInfo), Fp_i))
+			goto Do_Exit;
+
+		if(strcmp(pi->username, name) == 0) {
+			if(DeleteFullInfo(pi->FullInfo_ID) == 0)
+				goto Do_Exit;
+
+			if(DeleteUInfo(idx) == 0)
+				goto Do_Exit;
+
+			if(DeleteStringFromHashedIndex(name) != HASHINDEX_ER_OK)
+				goto Do_Exit;
+
+			// update user count
+			if(wcfseek(Fp_i, sizeof(DWORD), SEEK_SET) != 0)
+				goto Do_Exit;
+			if(!fCheckedRead(&ucount, sizeof(ucount), Fp_i))
+				goto Do_Exit;
+			ucount++;
+			if(wcfseek(Fp_i, sizeof(DWORD), SEEK_SET) != 0)
+				goto Do_Exit;
+			if(!fCheckedWrite(&ucount, sizeof(ucount), Fp_i))
+				goto Do_Exit;
+
+			unlock_file(Fp_i);
+			unlock_file(Fp_b);
+			/******** unlock Fp_i, Fp_b ********/
+
+			wcfclose(Fp_i);
+			wcfclose(Fp_b);
+
+			free(pi);
+			return PROFILE_RETURN_ALLOK;
+		}
+
+		unlock_file(Fp_i);
+		unlock_file(Fp_b);
+		/******** unlock Fp_i, Fp_b ********/
+
+		wcfclose(Fp_i);
+		wcfclose(Fp_b);
+
+		free(pi);
+		return PROFILE_RETURN_INVALID_LOGIN;
+
+	case HASHINDEX_ER_FORMAT:
+		return PROFILE_RETURN_INVALID_LOGIN;
+
+	case HASHINDEX_ER_IO_READ:
+	case HASHINDEX_ER_IO_CREATE:
+		goto Do_Exit;
+
+	default:
+		return PROFILE_RETURN_UNKNOWN_ERROR;
+	}
+
+Do_Exit:
+
+	if(Fp_i) {
+		unlock_file(Fp_i);
+		wcfclose(Fp_i);
+	}
+	if(Fp_b) {
+		unlock_file(Fp_b);
+		wcfclose(Fp_b);
+	}
+
+	return PROFILE_RETURN_DB_ERROR;
+}
+
+/* modify structures, user  if user exist, UserName cannot be changed
+ * return PROFILE_RETURN_ALLOK if successfull, otherwise standart error codes
+ * also if Fui is NULL, ModifyUser() will not modify Full User Information
+ */
+int CProfiles::ModifyUser(SProfile_UserInfo *newprf, SProfile_FullUserInfo *FullUI, DWORD *ui_index)
+{
+	DWORD ret, idx;
+	SProfile_UserInfo *pi;
+	Fp_i = NULL;
+	Fp_b = NULL;
+
+	if(!isLoginStrValid(newprf->username) || strlen(newprf->username) < 3)
+		return PROFILE_RETURN_INVALID_LOGIN;
+
+	ret = GetIndexOfString(newprf->username, &idx);
+
+	switch(ret) {
+	case HASHINDEX_ER_NOT_FOUND:
+		return PROFILE_RETURN_INVALID_LOGIN;
+
+	case HASHINDEX_ER_OK:
+		pi = (SProfile_UserInfo*)malloc(sizeof(SProfile_UserInfo));
+
+		// index exist - try to read block
+		if((Fp_i = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+			goto Do_Exit;
+
+		if((Fp_b = wcfopen(F_PROF_BODY, FILE_ACCESS_MODES_RW)) == NULL)
+			goto Do_Exit;
+		
+		/********* lock Fp_i, Fp_b *********/
+		lock_file(Fp_i);
+		lock_file(Fp_b);
+
+		if(wcfseek(Fp_i, idx, SEEK_SET) != 0)
+			goto Do_Exit;
+			
+		if(!fCheckedRead(pi, sizeof(SProfile_UserInfo), Fp_i))
+			goto Do_Exit;
+
+		if(strcmp(pi->username, newprf->username) == 0) {
+
+			if(wcfseek(Fp_i, idx, SEEK_SET) != 0) goto Do_Exit;
+			
+			if(ui_index != NULL) *ui_index = idx;
+
+			if(FullUI != NULL) {
+				// delete old and save new full info
+				if(DeleteFullInfo(pi->FullInfo_ID) == 0)
+					goto Do_Exit;
+
+				if(WriteFullInfo(&(newprf->FullInfo_ID), FullUI) == 0)
+					goto Do_Exit;
+			}
+			else {
+				newprf->FullInfo_ID = pi->FullInfo_ID;
+			}
+
+			// save old dinamic board information
+			newprf->postcount = pi->postcount;
+			newprf->UniqID = pi->UniqID;
+			newprf->persmsg = pi->persmsg;
+			newprf->lastIP = pi->lastIP;
+			newprf->persmescnt = pi->persmescnt;
+			newprf->readpersmescnt = pi->readpersmescnt;
+			newprf->postedmescnt = pi->postedmescnt;
+			newprf->postedpersmsg = pi->postedpersmsg;
+			newprf->RefreshCount = pi->RefreshCount;
+
+			// and finally save user profile
+			if(!fCheckedWrite(newprf, sizeof(SProfile_UserInfo), Fp_i))
+				goto Do_Exit;
+
+			unlock_file(Fp_i);
+			unlock_file(Fp_b);
+			/******** unlock Fp_i, Fp_b ********/
+
+			wcfclose(Fp_i);
+			wcfclose(Fp_b);
+
+			free(pi);
+			return PROFILE_RETURN_ALLOK;
+		}
+
+		unlock_file(Fp_i);
+		unlock_file(Fp_b);
+		/******** unlock Fp_i, Fp_b ********/
+
+		wcfclose(Fp_i);
+		wcfclose(Fp_b);
+
+		free(pi);
+		return PROFILE_RETURN_INVALID_LOGIN;
+
+	case HASHINDEX_ER_FORMAT:
+		return PROFILE_RETURN_INVALID_LOGIN;
+
+	case HASHINDEX_ER_IO_READ:
+	case HASHINDEX_ER_IO_CREATE:
+		goto Do_Exit;
+
+	default:
+		return PROFILE_RETURN_UNKNOWN_ERROR;
+	}
+
+Do_Exit:
+
+	if(Fp_i) {
+		unlock_file(Fp_i);
+		wcfclose(Fp_i);
+	}
+	if(Fp_b) {
+		unlock_file(Fp_b);
+		wcfclose(Fp_b);
+	}
+
+	return PROFILE_RETURN_DB_ERROR;
+}
+
+/* check, if there is user with same name in profile database
+ * return PROFILE_RETURN_ALLOK if successfull, otherwise standart error codes
+ * also if ui not NULL return SProfile_UserInfo for found user, and if also Fui not NULL
+ * return Fui information too
+ */
+int CProfiles::GetUserByName(char *name, SProfile_UserInfo *ui, SProfile_FullUserInfo *Fui, DWORD *ui_index)
+{
+	DWORD ret, idx;
+	SProfile_UserInfo *pi;
+
+	ret = GetIndexOfString(name, &idx);
+	// error code returned - next strings - analizing it
+
+	switch(ret) {
+	case HASHINDEX_ER_NOT_FOUND:
+		return PROFILE_RETURN_INVALID_LOGIN;
+
+	case HASHINDEX_ER_OK:
+		pi = (SProfile_UserInfo*)malloc(sizeof(SProfile_UserInfo));
+
+		// index exist - try to read block
+		if((Fp_i = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_R)) == NULL)
+			goto Do_Exit;
+
+		if((Fp_b = wcfopen(F_PROF_BODY, FILE_ACCESS_MODES_R)) == NULL)
+			goto Do_Exit;
+		
+		if(wcfseek(Fp_i, idx, SEEK_SET) != 0)
+			goto Do_Exit;
+
+		if(!fCheckedRead(pi, sizeof(SProfile_UserInfo), Fp_i))
+			goto Do_Exit;
+
+		if(strcmp(pi->username, name) == 0) {
+			// profile found
+					
+			if(ui != NULL) {
+				memcpy(ui, pi, sizeof(*pi));
+			}
+			if(Fui != NULL) {
+				// read SProfile_FullUserInfo
+				if(ReadFullInfo(pi->FullInfo_ID, Fui) == 0)
+					goto Do_Exit;
+			}
+			if(ui_index != NULL) *ui_index = idx;
+
+			free(pi);
+			wcfclose(Fp_b);
+			wcfclose(Fp_i);
+			return PROFILE_RETURN_ALLOK;
+			
+		}
+
+		/* name not found - not exist */
+		free(pi);
+		wcfclose(Fp_b);
+		wcfclose(Fp_i);
+		return PROFILE_RETURN_INVALID_LOGIN;
+
+	case HASHINDEX_ER_FORMAT:
+		return PROFILE_RETURN_INVALID_LOGIN;
+
+	case HASHINDEX_ER_IO_READ:
+	case HASHINDEX_ER_IO_CREATE:
+		goto Do_Exit;
+
+	default:
+		return PROFILE_RETURN_UNKNOWN_ERROR;
+	}
+
+Do_Exit:
+
+	return PROFILE_RETURN_DB_ERROR;
+}
+
+int CProfiles::GetUsersCount(DWORD *uc)
+{
+	if((Fp_i = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+		return 0;
+
+	if(wcfseek(Fp_i, sizeof(DWORD), SEEK_SET) != 0)
+		return 0;
+	if(!fCheckedRead(uc, sizeof(DWORD), Fp_i))
+		return 0;
+
+	wcfclose(Fp_i);
+	return 1;
+}
+
+int CProfiles::GetUInfo(DWORD idx, SProfile_UserInfo *FI)
+{
+	if((Fp_i = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_R)) == NULL)
+		return 0;
+	register DWORD x = (ReadUInfo(idx, FI) != 1);
+	wcfclose(Fp_i);
+	if(x) return 0;
+	return 1;
+}
+
+int CProfiles::SetUInfo(DWORD idx, SProfile_UserInfo *FI)
+{
+	if((Fp_i = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_RW)) == NULL)
+		return 0;
+	lock_file(Fp_i);
+	register DWORD x = (WriteUInfo(idx, FI) != 1);
+	unlock_file(Fp_i);
+	wcfclose(Fp_i);
+	if(x) return 0;
+	return 1;
+}
+
+int CProfiles::GetFullInfo(DWORD idx, SProfile_FullUserInfo *FI)
+{
+	if((Fp_b = wcfopen(F_PROF_BODY, FILE_ACCESS_MODES_R)) == NULL)
+		return 0;
+	register DWORD x = (ReadFullInfo(idx, FI) != 1);
+	wcfclose(Fp_b);
+	if(x) return 0;
+	return 1;
+}
+
+int CProfiles::GenerateUserList(char ***buf, DWORD *cnt)
+{
+	DWORD *ii;
+	DWORD readed, i, curii = 0, c = 0, ac /* alloced count */, allc = 0;
+#define ULIST_PROFILE_READ_COUNT 400
+	SProfile_UserInfo pi[ULIST_PROFILE_READ_COUNT];
+
+	*buf = NULL;
+	*cnt = 0;
+	if(GenerateIndexList(&ii) != HASHINDEX_ER_OK)
+		return 0;
+
+	if(ii[0] != 0xffffffff) {
+		*buf = (char**)malloc(ULIST_PROFILE_READ_COUNT*sizeof(char**));
+		if(!(*buf)) return 0;
+		ac = ULIST_PROFILE_READ_COUNT;
+
+		if((Fp_i = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_R)) == NULL) {
+			free(*buf);
+			*buf = NULL;
+			return 0;
+		}
+
+		if(wcfseek(Fp_i, ii[0], SEEK_SET) != 0)
+			return 0;
+
+		do {
+			readed = (DWORD)wcfread(&pi, 1, sizeof(SProfile_UserInfo)*ULIST_PROFILE_READ_COUNT, Fp_i);
+			if((readed % sizeof(SProfile_UserInfo)) != 0) {
+				wcfclose(Fp_i);
+				for(i = 0; i < c; i++) {
+					free((*buf)[i]);
+				}
+				free(*buf);
+				*buf = NULL;
+				return 0;
+			}
+			readed = readed / sizeof(SProfile_UserInfo);
+			
+			for(i = 0; i < readed; i++) {
+				// find this in our indexes (test for deleted profile)
+				while(ii[curii] < ((i + allc*ULIST_PROFILE_READ_COUNT)*sizeof(SProfile_UserInfo) + ii[0])) curii++;
+				if(ii[curii] == ((i + allc*ULIST_PROFILE_READ_COUNT)*sizeof(SProfile_UserInfo) + ii[0])) {
+					// modify right - reset all right if SUPERUSER
+					if((pi[i].right & USERRIGHT_SUPERUSER))
+						pi[i].right = USERRIGHT_SUPERUSER;
+					// store it
+					int len = (int)strlen(pi[i].username) + 1;
+					(*buf)[c] = (char*)malloc(len + 5*sizeof(DWORD) + 1);
+					memcpy(((char*)((*buf)[c])), &pi[i].lastIP, sizeof(DWORD));
+					memcpy(((char*)((*buf)[c])) + 4, &pi[i].postcount, sizeof(DWORD));
+					memcpy(((char*)((*buf)[c])) + 8, &pi[i].LoginDate, sizeof(DWORD));
+					memcpy(((char*)((*buf)[c])) + 12, &pi[i].RefreshCount, sizeof(DWORD));
+					memcpy(((char*)((*buf)[c])) + 16, &pi[i].right, sizeof(DWORD));
+					memcpy(((char*)((*buf)[c])) + 20, &pi[i].username, len);
+					c++;
+					// check for realloc
+					if(ac == c) {
+						ac += ULIST_PROFILE_READ_COUNT;
+						*buf = (char**)realloc(*buf, ac*sizeof(char**));
+					}
+				}
+				// FOR DEBUG !!!
+				/*else {
+					if(curii > 3) {
+						for(int j = -3; j < 4; j++) {
+							print2log("%d", ii[curii + j]);
+						}
+						print2log("i=%d, name=%s, Done\n", (i + allc*ULIST_PROFILE_READ_COUNT)*sizeof(SProfile_UserInfo) + ii[0], pi[i].username);
+					}
+				}*/
+			}
+			allc++;
+		} while(readed == ULIST_PROFILE_READ_COUNT);
+
+		wcfclose(Fp_i);
+
+		free(ii);
+		// realloc to the real size
+		*buf = (char**)realloc(*buf, c*sizeof(char**));
+
+		*cnt = c;
+	}
+
+	return 1;
+}
+
+int CProfiles::PostPersonalMessage(char *username, DWORD userindex, char *message, char *from, DWORD userindexfrom)
+{
+	SProfile_UserInfo ui, poster_ui;
+	int ret;
+	WCFILE *fp;
+
+	// load recipient user profile
+	if(username != NULL && strcmp(username, "") != 0) {
+		// use username
+		if((ret = GetUserByName(username, &ui, NULL, &userindex)) != PROFILE_RETURN_ALLOK)
+			return ret;
+	}
+	else {
+		// use userindex
+		if(!GetUInfo(userindex, &ui))
+			return PROFILE_RETURN_DB_ERROR;
+	}
+
+	// load sender user profile
+	if(from != NULL && strcmp(from, "") != 0) {
+		// use username
+		if((ret = GetUserByName(from, &poster_ui, NULL, &userindexfrom)) != PROFILE_RETURN_ALLOK)
+			return ret;
+	}
+	else {
+		// use userindex
+		if(!GetUInfo(userindexfrom, &poster_ui))
+			return PROFILE_RETURN_DB_ERROR;
+	}
+
+	// prepare personal message structure
+	SPersonalMessage mes;
+	DWORD pos;
+	mes.Date = time(NULL);
+	strcpy(mes.NameFrom, poster_ui.username);
+	mes.UIdFrom = poster_ui.UniqID;
+	strcpy(mes.NameTo, ui.username);
+	mes.UIdTo = ui.UniqID;
+	strcpy(mes.Msg, message);
+	mes.Prev = ui.persmsg;
+	mes.PosterPrev = poster_ui.postedpersmsg;
+
+	if((fp = wcfopen(F_PROF_PERSMSG, FILE_ACCESS_MODES_RW)) == NULL)
+		return PROFILE_RETURN_DB_ERROR;
+	lock_file(fp);
+	// write to the file
+	if(wcfseek(fp, 0, SEEK_END) != 0)
+		goto PostPersMsg_Error;
+	pos = wcftell(fp);
+	if(!fCheckedWrite(&mes, sizeof(mes), fp))
+		goto PostPersMsg_Error;
+
+	// update recipient user profile
+	ui.persmsg = pos;
+	ui.persmescnt++;
+	SetUInfo(userindex, &ui);
+
+	// to correct bug with post to youself
+	if(poster_ui.UniqID == ui.UniqID)
+		memcpy(&poster_ui, &ui, sizeof(SProfile_UserInfo));
+
+	// update sender user profile
+	poster_ui.postedpersmsg = pos;
+	poster_ui.postedmescnt++;
+	SetUInfo(userindexfrom, &poster_ui);
+
+	unlock_file(fp);
+	wcfclose(fp);
+	return PROFILE_RETURN_ALLOK;
+
+PostPersMsg_Error:
+	unlock_file(fp);
+	wcfclose(fp);
+	return PROFILE_RETURN_DB_ERROR;
+}
+
+int CProfiles::ReadPersonalMessages(char *username, DWORD userindex,
+									SPersonalMessage **tomessages, DWORD *tocount,
+									SPersonalMessage **frommessages, DWORD *fromcount)
+{
+	SProfile_UserInfo ui;
+	int ret;
+	WCFILE *fp;
+	SPersonalMessage *msg;
+	DWORD toread, i, fromread, curpos;
+
+	if(username != NULL && strcmp(username, "") != 0) {
+		// use username
+		if((ret = GetUserByName(username, &ui, NULL, &userindex)) != PROFILE_RETURN_ALLOK)
+			return ret;
+	}
+	else {
+		// use userindex
+		if(!GetUInfo(userindex, &ui))
+			return PROFILE_RETURN_DB_ERROR;
+	}
+
+	msg = *tomessages = *frommessages = NULL;
+
+	// if we really need read to messages
+	if(tocount == NULL) {
+		// all messages
+		toread = ui.persmescnt;
+	}
+	else {
+		if(*tocount == 0) {
+			// only new messages
+			toread = ui.persmescnt - ui.readpersmescnt;
+		}
+		else {
+			// selected count
+			if(*tocount > ui.persmescnt)
+				*tocount = ui.persmescnt;
+			toread = *tocount;
+		}
+	}
+	if(!toread) {
+		*tomessages = NULL;
+		goto skip_to_msg_read;
+	}
+
+	msg = (SPersonalMessage*)malloc(toread*sizeof(SPersonalMessage));
+
+	if((fp = wcfopen(F_PROF_PERSMSG, FILE_ACCESS_MODES_R)) == NULL)
+		return PROFILE_RETURN_DB_ERROR;
+	curpos = ui.persmsg;
+	for(i = 0; i < toread; i++) {
+		if(wcfseek(fp, curpos, SEEK_SET) != 0)
+			goto PostPersMsg_Error;
+		if(!fCheckedRead(&(msg[i]), sizeof(SPersonalMessage), fp))
+			goto PostPersMsg_Error;
+		curpos = msg[i].Prev;
+		// this situation should not happen, but...
+		if(curpos == 0xffffffff) break;
+	}
+	msg[toread - 1].Prev = 0xffffffff;	// last message mark
+	wcfclose(fp);
+	*tomessages = msg;
+	msg = NULL;
+
+skip_to_msg_read:
+
+	// if we really need read from messages
+	if(fromcount == NULL) {
+		// all messages
+		fromread = ui.postedmescnt;
+	}
+	else {
+		// selected count
+		if(*fromcount > ui.postedmescnt)
+			*fromcount = ui.postedmescnt;
+		fromread = *fromcount;
+	}
+	if(!fromread) {
+		*frommessages = NULL;
+		return PROFILE_RETURN_ALLOK;
+	}
+
+	msg = (SPersonalMessage*)malloc(fromread*sizeof(SPersonalMessage));
+
+	if((fp = wcfopen(F_PROF_PERSMSG, FILE_ACCESS_MODES_R)) == NULL)
+		return PROFILE_RETURN_DB_ERROR;
+	curpos = ui.postedpersmsg;
+	for(i = 0; i < fromread; i++) {
+		if(wcfseek(fp, curpos, SEEK_SET) != 0)
+			goto PostPersMsg_Error;
+		if(!fCheckedRead(&(msg[i]), sizeof(SPersonalMessage), fp))
+			goto PostPersMsg_Error;
+		curpos = msg[i].PosterPrev;
+		msg[i].Prev = 0;
+		// this situation should not happen, but...
+		if(curpos == 0xffffffff) {
+			break;
+		}
+	}
+	msg[i].Prev = 0xffffffff;	// last message mark
+	wcfclose(fp);
+	*frommessages = msg;
+
+	return PROFILE_RETURN_ALLOK;
+
+PostPersMsg_Error:
+	if(msg) free(msg);
+	if(*tomessages){
+		free(*tomessages);
+		*tomessages = NULL;
+	}
+	if(*frommessages){
+		free(*frommessages);
+		*frommessages = NULL;
+	}
+	wcfclose(fp);
+	return PROFILE_RETURN_DB_ERROR;
+}
+
+int CProfiles::ReadPersonalMessagesByDate(char *username, DWORD userindex,
+										  SPersonalMessage **tomessages, time_t todate,
+										  SPersonalMessage **frommessages, time_t fromdate)
+{
+	SProfile_UserInfo ui;
+	int ret;
+	WCFILE *fp;
+	SPersonalMessage *msg;
+	DWORD i, curpos;
+
+	if(username != NULL && strcmp(username, "") != 0) {
+		// use username
+		if((ret = GetUserByName(username, &ui, NULL, &userindex)) != PROFILE_RETURN_ALLOK)
+			return ret;
+	}
+	else {
+		// use userindex
+		if(!GetUInfo(userindex, &ui))
+			return PROFILE_RETURN_DB_ERROR;
+	}
+
+	msg = *tomessages = *frommessages = NULL;
+
+	// if we really need read "to" messages ?
+	if(!todate) {
+		*tomessages = NULL;
+		goto skip_to_msg_read;
+	}
+
+	if((fp = wcfopen(F_PROF_PERSMSG, FILE_ACCESS_MODES_R)) == NULL)
+		return PROFILE_RETURN_DB_ERROR;
+	msg = (SPersonalMessage*)malloc(sizeof(SPersonalMessage));
+	if(!msg) {
+		wcfclose(fp);
+		return PROFILE_RETURN_UNKNOWN_ERROR;
+	}
+	curpos = ui.persmsg;
+	i = 0;
+	if(curpos != 0xffffffff) {
+		for(0;;) {
+			if(wcfseek(fp, curpos, SEEK_SET) != 0)
+				goto PostPersMsg_Error;
+			if(!fCheckedRead(&(msg[i]), sizeof(SPersonalMessage), fp))
+				goto PostPersMsg_Error;
+			curpos = msg[i].Prev;
+			if(msg[i].Date < todate)
+				break;
+			i++;
+			if(curpos == 0xffffffff) break;
+			msg = (SPersonalMessage*)realloc(msg, (i+1)*sizeof(SPersonalMessage));
+		}
+	}
+	if(!i) {
+		free(msg);
+		msg = NULL;
+	}
+	else msg[i-1].Prev = 0xffffffff;	// last message mark
+	wcfclose(fp);
+	*tomessages = msg;
+	msg = NULL;
+
+skip_to_msg_read:
+
+	// if we really need read from messages
+	if(!fromdate) {
+		*frommessages = NULL;
+		return PROFILE_RETURN_ALLOK;
+	}
+
+	if((fp = wcfopen(F_PROF_PERSMSG, FILE_ACCESS_MODES_R)) == NULL)
+		return PROFILE_RETURN_DB_ERROR;
+	msg = (SPersonalMessage*)malloc(sizeof(SPersonalMessage));
+	if(!msg) {
+		wcfclose(fp);
+		return PROFILE_RETURN_UNKNOWN_ERROR;
+	}
+	curpos = ui.postedpersmsg;
+	i = 0;
+	if(curpos != 0xffffffff) {
+		for(;;) {
+			if(wcfseek(fp, curpos, SEEK_SET) != 0)
+				goto PostPersMsg_Error;
+			if(!fCheckedRead(&(msg[i]), sizeof(SPersonalMessage), fp))
+				goto PostPersMsg_Error;
+			curpos = msg[i].PosterPrev;
+			msg[i].Prev = 0;
+			if(msg[i].Date < fromdate)
+				break;
+			i++;
+			if(curpos == 0xffffffff) break;
+			msg = (SPersonalMessage*)realloc(msg, (i+1)*sizeof(SPersonalMessage));
+		}
+	}
+	if(!i) {
+		free(msg);
+		msg = NULL;
+	}
+	else msg[i - 1].Prev = 0xffffffff;	// last message mark
+	wcfclose(fp);
+	*frommessages = msg;
+
+	return PROFILE_RETURN_ALLOK;
+
+PostPersMsg_Error:
+	if(msg) free(msg);
+	if(*tomessages){
+		free(*tomessages);
+		*tomessages = NULL;
+	}
+	if(*frommessages){
+		free(*frommessages);
+		*frommessages = NULL;
+	}
+	wcfclose(fp);
+	return PROFILE_RETURN_DB_ERROR;
+}
+
+int CProfiles::CheckandAddFavsList(DWORD userindex, DWORD msgindex, int doadd)
+{
+	int i, empty=0, fl=0;
+	if( (msgindex == 0) || (userindex == 0)) return PROFILE_RETURN_INVALID_FORMAT;
+	SProfile_UserInfo ui;
+	if(!GetUInfo(userindex, &ui)) return PROFILE_RETURN_DB_ERROR;
+	for( i =0; i < PROFILES_FAV_THREADS_COUNT; i++){
+		if( ui.favs[i] == msgindex) return PROFILE_RETURN_ALREADY_EXIST;
+		if(ui.favs[i] == 0) { if(!empty) empty =i+1;}
+		else {if(ui.favs[i] < msgindex) fl=i+1;}
+	}
+	if( empty ){
+		if( doadd == 0) return PROFILE_RETURN_ALLOK;
+		DWORD prev=0;
+		for( i =0; i < PROFILES_FAV_THREADS_COUNT; i++){
+			if  (i > fl && i > empty) {
+				prev=ui.favs[PROFILES_FAV_THREADS_COUNT-1];
+				break;
+			}
+			if(i) ui.favs[i-1] = prev;
+			if(  (i - empty + 2 > 0)   &&  (i - fl + 1 < 0) ) {
+				prev=ui.favs[i+1];
+				continue;
+			}
+			if( ((i - fl + 1 > 0) && (i - empty < 0)) || ((i -fl +1 == 0) && (i - empty + 2 > 0)) ) {
+				prev=msgindex;
+				msgindex=ui.favs[i];
+				continue;
+			}
+			prev=ui.favs[i];
+		}
+		ui.favs[PROFILES_FAV_THREADS_COUNT-1]=prev;
+		if(SetUInfo(userindex, &ui)) return PROFILE_RETURN_ALLOK;
+		return PROFILE_RETURN_DB_ERROR;
+	}
+	return PROFILE_RETURN_UNKNOWN_ERROR;
+}
+
+int CProfiles::DelFavsList(DWORD userindex, DWORD msgindex)
+{
+	DWORD i;
+	if( (msgindex == 0) || (userindex == 0)) return PROFILE_RETURN_INVALID_FORMAT;
+	SProfile_UserInfo ui;
+	if(!GetUInfo(userindex, &ui)) return PROFILE_RETURN_DB_ERROR;
+
+	for( i =0; i < PROFILES_FAV_THREADS_COUNT; i++){
+		//check if msg is saved here and deleting if
+		if(ui.favs[i] == msgindex) {
+			ui.favs[i] = 0;
+			if(SetUInfo(userindex, &ui)) return PROFILE_RETURN_ALLOK;
+			return PROFILE_RETURN_DB_ERROR;
+		}
+	}
+	return PROFILE_RETURN_UNKNOWN_ERROR;
+}
blob - /dev/null
blob + 6989385930c05a238fd0dffb49801ff17a0c97d8 (mode 644)
--- /dev/null
+++ src/profiles.h
@@ -0,0 +1,202 @@
+/***************************************************************************
+                          profiles.h  -  profiles support include
+                             -------------------
+    begin                : Wed Mar 14 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef PROFILES_H_INCLUDED
+#define PROFILES_H_INCLUDED
+
+#include "basetypes.h"
+#include "hashindex.h"
+
+/* database length parameters */
+#define PROFILES_MAX_PASSWORD_LENGTH			33	
+#define PROFILES_MAX_ICQ_LEN					16
+#define PROFILES_MAX_ALT_DISPLAY_NAME			90
+#define PROFILES_FAV_THREADS_COUNT				20	//4*20 = 80 bytes real size
+#define PROFILES_MAX_USERNAME_LENGTH			30
+#define PROFILES_MAX_SIGNATURE_LENGTH			255
+#define PROFILES_FULL_USERINFO_MAX_NAME			255
+#define PROFILES_FULL_USERINFO_MAX_EMAIL		255
+#define PROFILES_FULL_USERINFO_MAX_HOMEPAGE		70
+#define PROFILES_FULL_USERINFO_MAX_SELECTEDUSR	185
+
+#define PROFILES_MIN_PASSWORD_LENGTH			3
+
+/* bit mask for user flags */
+#define PROFILES_FLAG_HAVE_PICTURE			0x0001
+#define PROFILES_FLAG_HAVE_SIGNATURE		0x0002
+#define PROFILES_FLAG_INVISIBLE				0x0004
+#define PROFILES_FLAG_VISIBLE_EMAIL			0x0008
+#define PROFILES_FLAG_NOT_ACTIVATED			0x0010
+#define PROFILES_FLAG_VIEW_SETTINGS			0x0020
+#define PROFILES_FLAG_DISABLED				0x0040
+#define PROFILES_FLAG_PERSMSGDISABLED		0x0080
+#define PROFILES_FLAG_PERSMSGTOEMAIL		0x0100
+#define PROFILES_FLAG_ALWAYS_EMAIL_ACKN	0x0200
+#define PROFILES_FLAG_ALT_DISPLAY_NAME		0x0400
+#define PROFILES_FLAG_APPLY_CONF_LOGIN		0x0800
+
+
+/* profile function error codes */
+#define PROFILE_RETURN_ALLOK			0
+#define	PROFILE_RETURN_ALREADY_EXIST	1
+#define PROFILE_RETURN_DB_ERROR			3
+#define PROFILE_RETURN_INVALID_FORMAT	4
+#define PROFILE_RETURN_INVALID_LOGIN	5
+#define PROFILE_RETURN_INVALID_PASSWORD	6
+#define PROFILE_RETURN_PASSWORD_SHORT	7
+#define PROFILE_RETURN_UNKNOWN_ERROR	9
+
+#define PROFILE_LOGIN_MIN_LENGTH		3
+
+#define PROFILE_NO_NEXT_INDEX			0xFFFFFFFF
+
+#define PROFILE_WASTED_FINFO_SIZE	sizeof(SProfile_FullUserInfo) - sizeof(char*)
+
+#define PROFILE_PERSONAL_MESSAGE_LENGHT	385
+
+struct SPersonalMessage {
+	DWORD Prev;
+	DWORD PosterPrev;
+	char NameFrom[PROFILES_MAX_USERNAME_LENGTH];
+	DWORD UIdFrom;
+	char NameTo[PROFILES_MAX_USERNAME_LENGTH];
+	DWORD UIdTo;
+	time_t Date;
+	char Msg[PROFILE_PERSONAL_MESSAGE_LENGHT];
+};
+
+
+#ifdef WIN32
+#pragma pack(push, 1)
+#else
+#pragma pack(1)
+#endif
+
+struct SViewSettings
+{
+	WORD dsm;
+	DWORD topics;
+	WORD tv;
+	WORD tc;
+	unsigned char ss:3;
+	unsigned char lsel:2;
+	unsigned char tt:4;
+	char tz:5;
+	unsigned char resrvd:2;
+};
+
+/* Full user information */
+struct SProfile_FullUserInfo {
+	char FullName[PROFILES_FULL_USERINFO_MAX_NAME];
+	char Email[PROFILES_FULL_USERINFO_MAX_EMAIL];
+	char HomePage[PROFILES_FULL_USERINFO_MAX_HOMEPAGE];
+	char SelectedUsers[PROFILES_FULL_USERINFO_MAX_SELECTEDUSR];
+	char Signature[PROFILES_MAX_SIGNATURE_LENGTH];
+
+	time_t CreateDate;
+
+	// Here you can define additional parameters
+
+	// do not modify following 2 lines
+	DWORD size;
+	char *AboutUser;
+};
+
+/* Structure which keep information about user in profiles database */
+struct SProfile_UserInfo {
+	/* Username, password */
+	char username[PROFILES_MAX_USERNAME_LENGTH];
+	char password[PROFILES_MAX_PASSWORD_LENGTH];
+	/* view settings */
+	SViewSettings vs;
+	char icqnumber[PROFILES_MAX_ICQ_LEN];
+	char altdisplayname[PROFILES_MAX_ALT_DISPLAY_NAME];
+	DWORD favs[PROFILES_FAV_THREADS_COUNT];
+	// count of refresh of this board
+	DWORD RefreshCount;
+	// recieved persmsg read count
+	WORD readpersmescnt;
+	// received persmsg current count
+	WORD persmescnt;
+	// posted persmsg count
+	WORD postedmescnt;
+	// personal message index (or 0xFFFFFFFF if does not exist)
+	DWORD persmsg;
+	// posted personal message index (or 0xFFFFFFFF)
+	DWORD postedpersmsg;
+	// user status
+	BYTE Status;
+	// Ip of last login
+	DWORD lastIP;
+	// security level for message header
+	BYTE secheader;
+	BYTE align1[3];
+	// unique user identifier
+	DWORD UniqID;
+	// flags for user (ex: have picture... etc.)
+	DWORD Flags;
+	// security level of user (for message body)
+	BYTE secur;
+	BYTE align2[3];
+	// right for user
+	DWORD right;
+	// number of posts to conference
+	DWORD postcount;
+	time_t LoginDate;
+	// index in profile bodies file of structure with common user information
+	DWORD FullInfo_ID;
+};
+#ifdef WIN32
+#pragma pack(pop)
+#else
+#pragma pack(4)
+#endif
+
+class CProfiles {
+protected:
+	WCFILE *Fp_i,	// profiles index file
+		*Fp_b;		// profiles body file
+
+	int ReadFullInfo(DWORD idx, SProfile_FullUserInfo *FI);
+	int WriteFullInfo(DWORD *idx, SProfile_FullUserInfo *FI);
+	int DeleteFullInfo(DWORD idx);
+
+	int GetSpaceforUInfo(DWORD *idx);
+	int WriteUInfo(DWORD idx, SProfile_UserInfo *FI);
+	int DeleteUInfo(DWORD idx);
+	int ReadUInfo(DWORD idx, SProfile_UserInfo *FI);
+public:
+	DWORD errnum;
+	CProfiles();
+	~CProfiles();
+
+	int AddNewUser(SProfile_UserInfo *newprf, SProfile_FullUserInfo *FullUI, DWORD *ui_index);
+	int ModifyUser(SProfile_UserInfo *newprf, SProfile_FullUserInfo *FullUI, DWORD *ui_index);
+	int DeleteUser(char *name);
+	int GetUserByName(char *name, SProfile_UserInfo *ui, SProfile_FullUserInfo *Fui, DWORD *ui_index);
+
+	// personal messages
+	int PostPersonalMessage(char *username, DWORD userindex, char *message, char *from, DWORD userindexfrom);
+	int ReadPersonalMessages(char *username, DWORD userindex,
+			SPersonalMessage **tomessages, DWORD *tocount, SPersonalMessage **frommessages, DWORD *fromcount);
+
+	int ReadPersonalMessagesByDate(char *username, DWORD userindex,
+			SPersonalMessage **tomessages, time_t todate, SPersonalMessage **frommessages, time_t fromdate);
+
+	int GenerateUserList(char ***buf, DWORD *cnt);
+
+	int GetUsersCount(DWORD *uc);
+	int GetUInfo(DWORD idx, SProfile_UserInfo *FI);
+	int SetUInfo(DWORD idx, SProfile_UserInfo *FI);
+	int GetFullInfo(DWORD idx, SProfile_FullUserInfo *FI);
+
+	int CheckandAddFavsList(DWORD userindex, DWORD msgindex, int doadd);
+	int DelFavsList(DWORD userindex, DWORD msgindex);
+};
+
+#endif
blob - /dev/null
blob + 7078bf2e0007902306bb99f956b395a32677cd33 (mode 644)
--- /dev/null
+++ src/profman.cpp
@@ -0,0 +1,822 @@
+/***************************************************************************
+                    profman.cpp  -  profile and database management tool
+                             -------------------
+    begin                : Wed May 14 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "profiles.h"
+#include "searcher.h"
+
+#define DIR_CREATION_MASK	511
+#define FILES_CREATION_MASK 511
+
+void printusage(char *iam)
+{
+	printf("Usage:\n\t %s -n              - create/renew database (create new messages and profiles database)\n" \
+				   "\t %s -nu             - create/renew ONLY profiles database (delete all profiles)\n" \
+				   "\t %s -nm             - create/renew ONLY messages database (delete all forum messages)\n" \
+				   "\t %s -dcheck         - check database consistency and print database information\n" \
+				   "\t %s -v user         - view user information for user 'username'\n" \
+				   "\t %s -vp username    - view all private messages for user 'username'\n" \
+				   "\t %s -aa user passwd - create admin (spec. username and password)\n" \
+				   "\t %s -au user passwd - create user (spec. username and password)\n" \
+				   "\t %s -d user         - delete user\n" \
+				   "\t %s -np             - renew(delete) private messages database (in profiles)\n" \
+				   "\t %s -r              - zero refresh count for all users\n" \
+				   "\t %s -vs             - set default view settings for all users\n" \
+				   "\t %s -sr [max_index] - create search index (up to max_index message, optional))\n" \
+				   "\t %s -s [word]       - search for word using index\n",
+				iam, iam, iam, iam, iam, iam, iam, iam, iam, iam, iam, iam, iam, iam);
+	exit(0);
+}
+
+int mmkdir(const char *s)
+{
+	int r;
+	char *ss;
+	if((ss = strchr(s, '/')) || (ss = strchr(s, '\\'))) {
+		char os[1000];
+		if(strlen(ss) > 1) {
+			strncpy(os, s, ss - s);
+			os[ss - s] = 0;
+#ifdef WIN32
+			mkdir(os);
+#else
+			mkdir(os, DIR_CREATION_MASK);
+#endif
+		}
+		if((r =
+#ifdef WIN32
+			mkdir(s)
+#else
+			mkdir(s, DIR_CREATION_MASK)
+#endif
+		) != 0)
+			return r;
+	}
+	return r;
+}
+
+
+void printuserrigth(DWORD r)
+{
+	printf("User right: ");
+	int smthprinted = 0;
+	if(r & USERRIGHT_SUPERUSER) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("SuperUser");
+	}
+	if(r & USERRIGHT_VIEW_MESSAGE) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("View message");
+	}
+	if(r & USERRIGHT_MODIFY_MESSAGE) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("Modify own message");
+	}
+	if(r & USERRIGHT_CLOSE_MESSAGE) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("Close own message thread");
+	}
+	if(r & USERRIGHT_OPEN_MESSAGE) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("Open own message thread");
+	}
+	if(r & USERRIGHT_CREATE_MESSAGE) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("Reply on message");
+	}
+	if(r & USERRIGHT_CREATE_MESSAGE_THREAD) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("Create new message thread");
+	}
+	if(r & USERRIGTH_ALLOW_HTML) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("Allow HTML");
+	}
+	if(r & USERRIGTH_PROFILE_MODIFY) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("Own Profile modification");
+	}
+	if(r & USERRIGTH_PROFILE_CREATE) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("New profile creation");
+	}
+	if(r & USERRIGHT_ROLL_MESSAGE) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("Roll own messages");
+	}
+	if(r & USERRIGHT_UNROLL_MESSAGE) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("Unroll own messages");
+	}
+	if(r & USERRIGHT_POST_GLOBAL_ANNOUNCE) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("Post global announce");
+	}
+	if(r & USERRIGHT_ALT_DISPLAY_NAME) {
+		if(smthprinted) printf(", ");
+		else smthprinted = 1;
+		printf("Alternative name");
+	}
+	printf("\n");
+}
+
+void printerror(DWORD er)
+{
+	printf("Result: ");
+	switch(er) {
+	case PROFILE_RETURN_ALLOK:
+		printf("All ok\n");
+	case PROFILE_RETURN_ALREADY_EXIST:
+		printf("User already exits\n");
+		break;
+	case PROFILE_RETURN_DB_ERROR:
+		printf("Database error\n");
+		break;
+	case PROFILE_RETURN_INVALID_FORMAT:
+		printf("Invalid file format\n");
+		break;
+	case PROFILE_RETURN_INVALID_LOGIN:
+		printf("Invalid login name\n");
+		break;
+	case PROFILE_RETURN_INVALID_PASSWORD:
+		printf("Invalid password\n");
+		break;
+	case PROFILE_RETURN_PASSWORD_SHORT:
+		printf("Password too short\n");
+		break;
+	case PROFILE_RETURN_UNKNOWN_ERROR:
+		printf("Unknown database error\n");
+		break;
+	}
+}
+
+int CreateProfilesDatabase()
+{
+	FILE *f;
+	if((f = fopen(F_PROF_NINDEX, FILE_ACCESS_MODES_CW)) == NULL) {
+		printf("Error creating Database file : %s\n" \
+			"Please make sure you have necessary directory structure\n",
+			F_PROF_NINDEX);
+		return 0;
+	}
+	else {
+		DWORD x = 0;
+		fwrite(&x, 1, sizeof(x), f);
+		fwrite(&x, 1, sizeof(x), f);
+		fclose(f);
+	}
+	if((f = fopen(F_PROF_FREENIDX, FILE_ACCESS_MODES_CW)) == NULL) {
+		printf("Error creating profiles database file : %s\n", F_PROF_FREENIDX);
+		return 0;
+	}
+	else fclose(f);
+	if((f = fopen(F_PROF_BODY, FILE_ACCESS_MODES_CW)) == NULL) {
+		printf("Error creating profiles database file : %s\n", F_PROF_BODY);
+		return 0;
+	}
+	else fclose(f);
+	if((f = fopen(F_PROF_FREEBODY, FILE_ACCESS_MODES_CW)) == NULL) {
+		printf("Error creating profiles database file : %s\n", F_PROF_FREEBODY);
+		return 0;
+	}
+	else fclose(f);
+	if((f = fopen(F_PROF_PERSMSG, FILE_ACCESS_MODES_CW)) == NULL) {
+		printf("Error creating profiles database file : %s\n", F_PROF_PERSMSG);
+		return 0;
+	}
+	else fclose(f);
+
+	remove(F_PROF_INDEX);
+	if(AddStringToHashedIndex("aaa", 1) != HASHINDEX_ER_OK) {
+		printf("Error creating profiles database file : %s\n", F_PROF_INDEX);
+		return 0;
+	}
+	if(DeleteStringFromHashedIndex("aaa") != HASHINDEX_ER_OK) {
+		printf("Error creating profiles database file : %s\n", F_PROF_INDEX);
+		return 0;
+	}
+	return 1;
+}
+
+int CreateMessagesDatabase()
+{
+	FILE *f;
+	if((f = fopen(F_MSGINDEX, FILE_ACCESS_MODES_CW)) == NULL) {
+		printf("Error creating profiles database file : %s\n", F_MSGINDEX);
+		return 0;
+	}
+	else fclose(f);
+	if((f = fopen(F_MSGBODY, FILE_ACCESS_MODES_CW)) == NULL) {
+		printf("Error creating profiles database file : %s\n", F_MSGBODY);
+		return 0;
+	}
+	else fclose(f);
+	if((f = fopen(F_INDEX, FILE_ACCESS_MODES_CW)) == NULL) {
+		printf("Error creating profiles database file : %s\n", F_INDEX);
+		return 0;
+	}
+	else fclose(f);
+	if((f = fopen(F_VINDEX, FILE_ACCESS_MODES_CW)) == NULL) {
+		printf("Error creating profiles database file : %s\n", F_VINDEX);
+		return 0;
+	}
+	else fclose(f);
+	return 1;
+}
+
+int CheckAndCreateFolder(char *d, char *s)
+{
+	if(chdir(d) != 0) {
+		if(mmkdir(d) != 0) {
+			printf("Cannot create directory %s\n", d);
+			return 0;
+		}
+		else printf("%s created\n", d);
+	}
+	else {
+		// return to our folder
+		if(chdir(s) != 0) {
+			printf("Cannot change directory to %s\n", s);
+			return 0;
+		}
+	}
+	return 1;
+}
+
+int CreateFullDatabase()
+{
+	// alloc mem and save our current folder
+	char *s = (char*)malloc(2560);
+	if(getcwd(s, 2559) == NULL) {
+		printf("Cannot get current directory\n");
+		return 0;
+	}
+
+	if(!CheckAndCreateFolder(DIR_MAINDATA, s))
+		return 0;
+
+	if(!CheckAndCreateFolder(DIR_MESSAGES, s))
+		return 0;
+
+	if(!CheckAndCreateFolder(DIR_SEARCHER, s))
+		return 0;
+
+	if(!CheckAndCreateFolder(DIR_PROFILES, s))
+		return 0;
+
+	if(!CheckAndCreateFolder(DIR_PROF_PIC, s))
+		return 0;
+
+	if(!CheckAndCreateFolder(DIR_SETTINGS, s))
+		return 0;
+
+	if(!CheckAndCreateFolder(DIR_INTERNALS, s))
+		return 0;
+	free(s);
+
+	if(!CreateProfilesDatabase())
+		return 0;
+	if(!CreateMessagesDatabase())
+		return 0;
+
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	CProfiles *ul;
+	DWORD errcode;
+
+	SProfile_UserInfo ui;
+	WCFILE *fw;
+
+	ul = new CProfiles();
+	if(ul->errnum != PROFILE_RETURN_ALLOK) {
+	}
+	
+	printf("WWWConf console management tool\n");
+
+#if USE_LOCALE
+	if(setlocale(LC_ALL, LANGUAGE_LOCALE) == NULL) {
+		printf("Setting locale [%s] failed !\n", LANGUAGE_LOCALE);
+		printf("Bailing out to default locale \"C\"");
+		setlocale(LC_ALL, "C");
+	}
+#endif
+	
+	if(argc <= 1) {
+		goto go_end;
+	}
+	if((strcmp(argv[1], "-au") == 0 || strcmp(argv[1], "-aa") == 0) && argc == 4) {
+		// create user
+		SProfile_UserInfo ui;
+		SProfile_FullUserInfo fui;
+		
+		strcpy(fui.Email, "");
+		strcpy(fui.FullName, argv[2]);
+		strcpy(fui.Signature, "");
+		strcpy(fui.HomePage, "");
+		strcpy(fui.SelectedUsers, "");
+		strcpy(ui.username, argv[2]);
+		strcpy(ui.password, argv[3]);
+		strcpy(ui.icqnumber, "");
+		strcpy(ui.altdisplayname, "");
+		fui.AboutUser = NULL;
+
+		ui.lastIP = 0;
+		ui.Flags = 0; // don't have picture or signature
+		if(strcmp(argv[1], "-aa") != 0) {
+			ui.right = DEFAULT_USER_RIGHT;
+			ui.secur = DEFAULT_USER_SECURITY_BYTE;
+			ui.secheader = DEFAULT_USER_HDR_SEC_BYTE;
+		}
+		else {
+			ui.right = DEFAULT_ADMIN_RIGHT;
+			ui.secur = DEFAULT_ADMIN_SECURITY_BYTE;
+			ui.secheader = DEFAULT_ADMIN_HDR_SEC_BYTE;
+		}
+
+		if((errcode = ul->AddNewUser(&ui, &fui, NULL)) == PROFILE_RETURN_ALLOK)
+			printf("User successfully created\n");
+		else printerror(errcode);
+		goto go_stop;
+	}
+
+	if(strcmp(argv[1], "-d") == 0 && argc == 3) {
+		if((errcode = ul->DeleteUser(argv[2])) == PROFILE_RETURN_ALLOK) {
+			printf("User successfully deleted\n");
+		}
+		else printerror(errcode);
+		goto go_stop;
+	}
+
+	if(strcmp(argv[1], "-v") == 0 && argc == 3) {
+		SProfile_FullUserInfo fui;
+		DWORD ind;
+		if(ul->errnum != PROFILE_RETURN_ALLOK) {
+			printf("Fatal: profiles database could not be accessed\n");
+			goto go_stop;
+		}
+		if((errcode = ul->GetUserByName(argv[2], &ui, &fui, &ind)) == PROFILE_RETURN_ALLOK) {
+			printf("User Information\n");
+			int sr = ui.secheader;
+			int srb = ui.secur;
+			printf("Login name : %s  Password : %s\n", ui.username, ui.password);
+			fui.SelectedUsers[PROFILES_FULL_USERINFO_MAX_SELECTEDUSR - 1] = 0;
+			printf("AltName : %s\n, Full name : %s, E-mail : %s\nSelected users: %s\nAbout : %s\nSignature: %s\n"
+				   "Flags: 0x%08x\nSecurity right byte (hdr) : %d\nSecurity right byte (body) : %d\nRefresh count : %d\n",
+				ui.altdisplayname, fui.FullName, fui.Email, fui.SelectedUsers, fui.AboutUser,
+				fui.Signature, ui.Flags, sr, srb, ui.RefreshCount);
+			printuserrigth(ui.right);
+			
+			char *s;
+			s = ctime(&fui.CreateDate);
+			printf("Creation date: %s\n", s);
+
+			int nf = 0;
+
+			if(ui.LoginDate != 0) s = ctime(&ui.LoginDate);
+			else {
+				nf = 1;
+				s = (char*)malloc(100);
+				strcpy(s, "Never logged in");
+			}	
+			printf("Last access date: %s\n", s);
+			if(nf) free(s);
+/*			ui.LoginDate -= 36000*7;
+			ul->SetUInfo(ind, &ui);*/
+		}
+		else printerror(errcode);
+		goto go_stop;
+	}
+
+	if(argc == 2 && strcmp(argv[1], "-np") == 0) {
+		printf("Renewing private messages database...\n");
+		if((fw = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_CW)) != NULL) {
+			wcfclose(fw);
+		}
+		else {
+			printf("Fatal: profiles database could not be accessed !!!\n");
+			return 0;
+		}
+		if((fw = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_RW)) != NULL) {
+			int i = 0;
+			lock_file(fw);
+			wcfseek(fw, 8, SEEK_SET);
+			while(!wcfeof(fw)) {
+				DWORD pos = wcftell(fw);
+				if(wcfread(&ui, 1, sizeof(SProfile_UserInfo), fw) < sizeof(SProfile_UserInfo))
+					break;
+				ui.persmescnt = 0;
+				ui.persmsg = 0xffffffff;
+				ui.readpersmescnt = 0;
+				ui.postedpersmsg = 0xffffffff;
+				ui.postedmescnt = 0;
+				wcfseek(fw, pos, SEEK_SET);
+				wcfwrite(&ui, 1, sizeof(SProfile_UserInfo), fw);
+				wcfseek(fw, wcftell(fw), SEEK_SET);
+				i++;
+			}
+			printf("%d users processed\n", i);
+			unlock_file(fw);
+			wcfclose(fw);
+			printf("Done!\n");
+		}
+		else printf("Fatal: profiles database could not be accessed !!!\n");
+		goto go_stop;
+	}
+
+	if(argc == 2 && strcmp(argv[1], "-r") == 0) {
+		printf("Clearing refresh count...\n");
+		if((fw = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_RW)) != NULL) {
+			int i = 0;
+			lock_file(fw);
+			wcfseek(fw, 8, SEEK_SET);
+			while(!wcfeof(fw)) {
+				DWORD pos = wcftell(fw);
+				if(wcfread(&ui, 1, sizeof(SProfile_UserInfo), fw) < sizeof(SProfile_UserInfo))
+					break;
+				ui.RefreshCount = 0;
+				wcfseek(fw, pos, SEEK_SET);
+				wcfwrite(&ui, 1, sizeof(SProfile_UserInfo), fw);
+				wcfseek(fw, wcftell(fw), SEEK_SET);
+				i++;
+			}
+			printf("%d users processed\n", i);
+			unlock_file(fw);
+			wcfclose(fw);
+			printf("Done!\n");
+		}
+		else printf("Fatal: profiles database couldn't be accessed !!!\n");
+		goto go_stop;
+	}
+
+	if(argc == 2 && strcmp(argv[1], "-vs") == 0) {
+		printf("Clearing view settings...\n");
+		if((fw = wcfopen(F_PROF_NINDEX, FILE_ACCESS_MODES_RW)) != NULL) {
+			int i = 0;
+			lock_file(fw);
+			wcfseek(fw, 8, SEEK_SET);
+			while(!wcfeof(fw)) {
+				DWORD pos = wcftell(fw);
+				if(wcfread(&ui, 1, sizeof(SProfile_UserInfo), fw) < sizeof(SProfile_UserInfo))
+					break;
+				
+			/*	ui.vs.dsm = CONFIGURE_SETTING_DEFAULT_dsm;
+				ui.vs.topics = CONFIGURE_SETTING_DEFAULT_topics;
+				ui.vs.tv = CONFIGURE_SETTING_DEFAULT_tv;
+				ui.vs.tc = CONFIGURE_SETTING_DEFAULT_tc;
+				ui.vs.ss = CONFIGURE_SETTING_DEFAULT_ss;
+				ui.vs.lsel = CONFIGURE_SETTING_DEFAULT_lsel;
+				ui.vs.tt = CONFIGURE_SETTING_DEFAULT_tt;
+				ui.icqnumber[0] = 0;
+				ui.Flags |= PROFILES_FLAG_VIEW_SETTINGS; 
+				ui.vs.tz = DATETIME_DEFAULT_TIMEZONE;
+				*/
+				ui.vs.topics  |= (1<<17);	
+		
+				wcfseek(fw, pos, SEEK_SET);
+				wcfwrite(&ui, 1, sizeof(SProfile_UserInfo), fw);
+				wcfseek(fw, wcftell(fw), SEEK_SET);
+				i++;
+			}
+			printf("%d users processed\n", i);
+			unlock_file(fw);
+			wcfclose(fw);
+			printf("Done!\n");
+		}
+		else printf("Fatal: profiles database couldn't be accessed !!!\n");
+		goto go_stop;
+	}
+
+	if(argc == 3 && strcmp(argv[1], "-vp") == 0) {
+		SPersonalMessage *topm, *frompm;
+		CProfiles prof;
+		int code;
+		if((code = prof.GetUserByName(argv[2], &ui, NULL, NULL)) != PROFILE_RETURN_ALLOK) {
+			printf("User not found!\n");
+			exit(0);
+		}
+		if((code = prof.ReadPersonalMessages(argv[2], 0, &topm, NULL, &frompm, NULL)) == PROFILE_RETURN_ALLOK) {
+			char tostr[1000], newm[100];
+			char *ss;
+			SPersonalMessage *pmsg;
+			int i = 0;
+			int j = 0;
+			int received = 0;	// posted or received
+			int cnt = 0, postedcnt = 0;
+			if(topm) {
+				while(topm[cnt].Prev != 0xffffffff) cnt++;
+				cnt++;
+			}
+			if(frompm) {
+				while(frompm[postedcnt].Prev != 0xffffffff) postedcnt++;
+				postedcnt++;
+			}
+			printf("        Messages for user %s\n", argv[2]);
+			for(;;) {
+				// check exit expression
+				if(i == cnt && j == postedcnt) break;
+				if(i == cnt) {
+					pmsg = &(frompm[j]);
+					j++;
+					received = 0;
+				} else {
+					if(j == postedcnt) {
+						pmsg = &(topm[i]);
+						i++;
+						received = 1;
+					}
+					else {
+						if(frompm[j].Date > topm[i].Date) {
+							pmsg = &(frompm[j]);
+							j++;
+							received = 0;
+						}
+						else {
+							pmsg = &(topm[i]);
+							i++;
+							received = 1;
+						}
+					} 
+				}
+	
+				if(!received) {
+					strcpy(tostr, pmsg->NameTo);
+				}
+				else {
+					strcpy(tostr, pmsg->NameFrom);
+				}
+
+				ss = ctime(&pmsg->Date);
+
+				if(received && i <= (ui.persmescnt - ui.readpersmescnt))
+					strcpy(newm, "Not readed");
+				else strcpy(newm, "");
+
+				if(!received) {
+					// posted message
+					printf("To user: %s, Date: %s\t\t\t%s", tostr, ss, newm);
+				}
+				else {
+					// received message
+					printf("From user: %s, Date: %s\t\t\t%s", tostr, ss, newm);
+				}
+
+				printf("%s\n\n", pmsg->Msg);
+			}
+		}
+		else printf("ReadPersonalMessages() returned error code: %x (%s)\n", code, (code == PROFILE_RETURN_INVALID_LOGIN) ? "unknown user" : "database error");
+		goto go_stop;
+	}
+
+	if(argc == 2 && strcmp(argv[1], "-nu") == 0) {
+		printf("Creating/Renewing profiles database...\n");
+		if(!CreateProfilesDatabase())
+			goto go_stop;
+		printf("Operation completed successfully\n");
+		goto go_stop;
+	}
+
+	if(argc == 2 && strcmp(argv[1], "-n") == 0) {
+		printf("Creating/Renewing profiles and messages databases...\n");
+		if(!CreateFullDatabase())
+			goto go_stop;
+		printf("Operation completed successfully\n");
+		goto go_stop;
+	}
+
+	if(argc == 2 && strcmp(argv[1], "-nm") == 0) {
+		printf("Creating/Renewing messages database...\n");
+		if(!CreateMessagesDatabase())
+			goto go_stop;
+		printf("Operation completed successfully\n");
+		goto go_stop;
+	}
+
+	if(argc == 2 && strcmp(argv[1], "-dcheck") == 0) {
+		printf("Checking profiles database...\n");
+#if 0
+		printf("Operation completed successfully\n");
+		printf("Checking messages database...\n");
+		printf("Operation completed successfully\n");
+#else
+		printf("Function not yet implemented!\n");
+#endif
+		goto go_stop;
+	}
+
+	if(strcmp(argv[1], "-s") == 0) {
+		if(argc == 3) {
+			CMessageSearcher *in = new CMessageSearcher(SEARCHER_INDEX_CREATE_EXISTING);
+			if(in->errnum != SEARCHER_RETURN_ALLOK) {
+				printf("Searcher init = failed\nMake sure that search index was created\n");
+				goto go_stop;
+			}
+			DWORD c;
+			DWORD *buf = in->SearchMessagesByPattern(argv[2], &c);
+			if(c > 0) {
+				printf("Found %ld matches in messages : ", c);
+				for(register DWORD i = 0; i < c; i++) {
+					printf("%ld ", buf[i]);
+				}
+				free(buf);
+			}
+			else {
+				printf("Found 0 matches");
+			}
+			printf("\n");
+			delete in;
+			goto go_stop;
+		}
+		else {
+			printf("Invalid parameters count for -s\n");
+			goto go_stop;
+		}
+	}
+
+	if(strcmp(argv[1], "-sr") == 0) {
+		DWORD StartMsg = 0, LastDate = 0, DBDirty = 0, StopIndex = 0;
+		CMessageSearcher *in = NULL;
+		SMessage *sm;
+		time_t now, start;
+		FILE *fl, *f, *f1, *f2;
+		if(argc == 2) {
+			StopIndex = 0xffffffff;
+		}
+		else {
+			char *st;
+			StopIndex = strtol(argv[2], &st, 10);
+			if(((!(*(argv[2]) != '\0' && *st == '\0')) || errno == ERANGE)) {
+				printf("Invalid parameter for -sr command\n");
+				goto go_stop;
+			}
+		}
+		
+		fl = fopen(F_SEARCH_LASTINDEX, FILE_ACCESS_MODES_RW);
+		if(fl != NULL) {
+			fscanf(fl, "%d %d", &StartMsg, &LastDate, &DBDirty);
+			fclose(fl);
+			if(DBDirty) {
+				printf("Database marked as dirty (another instance of indexer in progress?)\n", F_SEARCH_LASTINDEX);
+				goto go_stop;
+			}
+		}
+
+		// mark as dirty
+		fl = fopen(F_SEARCH_LASTINDEX, FILE_ACCESS_MODES_CW);
+		if(f != NULL) {
+			fprintf(fl, "%d %d %d", StartMsg, LastDate, 1);
+			fclose(fl);
+		}
+		else {
+			printf("Couldn't create status file %s\n", F_SEARCH_LASTINDEX);
+			goto go_stop;
+		}
+
+		if(StartMsg == 0) {
+			f = fopen(F_SEARCH_DB, FILE_ACCESS_MODES_CW);
+			if(f == NULL) {
+				printf("Error creating searcher database file %s\n", F_SEARCH_DB);
+				goto go_stop;
+			}
+			fclose(f);
+			in = new CMessageSearcher(SEARCHER_INDEX_CREATE_NEW);
+		}
+		else in = new CMessageSearcher(SEARCHER_INDEX_CREATE_EXISTING);
+		if(in->errnum != SEARCHER_RETURN_ALLOK) {
+			printf("Searcher init = failed\n");
+			goto go_stop;
+		}
+
+		sm = (SMessage*)malloc(sizeof(SMessage)*READ_MESSAGE_HEADER);
+		in->indexed_word_count = 0;
+
+		f = fopen(F_MSGINDEX, FILE_ACCESS_MODES_R);
+		f1 = fopen(F_MSGBODY, FILE_ACCESS_MODES_R);
+		f2 = fopen(F_VINDEX, FILE_ACCESS_MODES_R);
+
+		if(f == NULL || f1 == NULL || f2 == NULL) {
+			free(sm);
+			printf("Error opening database files\n");
+			goto go_stop;
+		}
+
+		DWORD rr, idx;
+		char *mbody;
+		DWORD wc = 0;
+		time_t tm = time(NULL);
+		printf("Indexing(starting from %ld), report format: NUM-SEC, NUM-processed mess, SEC-seconds last 100 mess were indexed", StartMsg);
+
+		if(fseek(f2, (StartMsg+1)*sizeof(DWORD), SEEK_SET) != 0) {
+			free(sm);
+			printf("Invalid starting index\n");
+			goto go_stop;
+		}
+
+		start = time(NULL);
+		while(!feof(f2)) {
+
+			if(StartMsg >= StopIndex) {
+				printf("Stopped at index %ld (StopIndex)", StartMsg);
+				break;
+			}
+
+			if(fread(&idx, 1, sizeof(DWORD), f2) != sizeof(DWORD)) {
+				break;
+			}
+			StartMsg++;
+
+			if(idx == 0xFFFFFFFF) continue;
+
+			if(fseek(f, idx, SEEK_SET) != 0) {
+				continue;
+			}
+			rr = (DWORD)fread(sm, 1, sizeof(SMessage), f);
+			if(rr != sizeof(SMessage) && rr != 0) {
+				printf("Error reading %s\n", F_MSGINDEX);
+				goto go_stop;
+			}
+			wc++;
+			in->InsertMessageToIndex(sm->MessageHeader, sm->ViIndex);
+
+			if((sm->Flag & MESSAGE_HAVE_BODY) != 0 && sm->msize > 2) {
+				DWORD readed;
+				mbody = (char*)malloc(sm->msize + 10);
+				if(fseek(f1, sm->MIndex, SEEK_SET) != 0) {
+					free(mbody);
+					continue;
+				}
+				if((readed = (DWORD)fread(mbody, 1, sm->msize + 2, f1)) < sm->msize) {
+					free(mbody);
+					continue;
+				}
+				mbody[readed] = 0;
+				if(sm->msize != 0 && *mbody == 0) {
+					char *ss = mbody;
+					ss++;
+					while(*ss) {
+						*(ss-1) = *(ss);
+						ss++;
+					}
+					*(ss-1) = *ss;
+				}
+				if(strlen(mbody) > 65000) {
+					printf("\nIncorrect DB format: Body of message %d is too long\n", sm->ViIndex);
+					goto go_stop;
+				}
+				in->InsertMessageToIndex(mbody, sm->ViIndex);
+				free(mbody);
+			}
+			if((wc % 100) == 0) {
+				now = time(NULL);
+				printf("%ld-%d.", wc, start - now);
+				start = now;
+				fflush(stdout);
+			}
+		}
+		fclose(f);
+		fclose(f1);
+		fclose(f2);
+		printf("\nDone at %ld\nFlusing cache...", StartMsg);
+		DWORD iww = in->indexed_word_count;
+		DWORD tcache = time(NULL);
+		delete in;
+		printf("done in %ld seconds\n", time(NULL) - tcache);
+
+		fl = fopen(F_SEARCH_LASTINDEX, FILE_ACCESS_MODES_CW);
+		if(f != NULL) {
+			fprintf(fl, "%d %d %d", StartMsg, LastDate, 0);
+			fclose(fl);
+		}
+
+		printf("\nFinished in %ld seconds, words indexed %ld\n", time(NULL) - tm, iww);
+		free(sm);
+		goto go_stop;
+	}
+
+go_end:
+	printf("Fatal: Invalid option was specified: %s\n\n", argv[1] ? argv[1] : "");
+	printusage(argv[0]);
+go_stop:
+	delete ul;
+	return 0;
+}
blob - /dev/null
blob + dad3646a31e0e95208285dad1ef2f5cd1e6854df (mode 644)
--- /dev/null
+++ src/reindex.cpp
@@ -0,0 +1,206 @@
+/***************************************************************************
+                          reindex.cpp  -  message index build tool
+                             -------------------
+    begin                : Wed Apr 29 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "searcher.h"
+
+void printusage(char *iam)
+{
+	printf("Usage:\n" \
+		   "          %s -r [max_index]      - index messages (up to max_index (optional))\n" \
+		   "          %s -s word             - search for word\n", iam, iam);
+	exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+	FILE *f, *f1, *f2, *fl;
+	DWORD StartMsg = 0, LastDate = 0, StopIndex = 0;
+	CMessageSearcher *in;
+	SMessage *sm;
+	time_t now, start;
+
+	printf("WWWConf search index builder\n");
+#if USE_LOCALE
+	if(setlocale(LC_ALL, LANGUAGE_LOCALE) == NULL) {
+		printf("Setting locale [%s] failed !\n", LANGUAGE_LOCALE);
+		printf("Bailing out to default locale \"C\"");
+		setlocale(LC_ALL, "C");
+	}
+#endif
+	if(argc < 2 || (argc >= 2 && strcmp(argv[1], "-r") != 0)) {
+		if(argc == 3 && strcmp(argv[1], "-s") == 0) {
+			in = new CMessageSearcher(SEARCHER_INDEX_CREATE_EXISTING);
+			if(in->errnum != SEARCHER_RETURN_ALLOK) {
+				printf("Searcher init = failed\n");
+				exit(0);
+			}
+			DWORD c;
+			DWORD *buf = in->SearchMessagesByPattern(argv[2], &c);
+			if(c > 0) {
+				printf("Found %ld matches in messages : ", c);
+				for(register DWORD i = 0; i < c; i++) {
+					printf("%ld ", buf[i]);
+				}
+				free(buf);
+			}
+			else {
+				printf("Found 0 matches");
+			}
+			printf("\n");
+			delete in;
+			exit(0);
+		}
+		else {
+			printusage(argv[0]);
+			exit(0);
+		}
+	}
+
+	if(argc != 3 && argc != 2) {
+		printusage(argv[0]);
+		exit(0);
+	}
+	if(argc == 3) {
+		char *st;
+		StopIndex = strtol(argv[2], &st, 10);
+		if(((!(*(argv[2]) != '\0' && *st == '\0')) || errno == ERANGE)) {
+			printusage(argv[0]);
+			exit(0);
+		}
+		else {
+			// correct value
+		}
+	}
+	else StopIndex = 0xffffffff;
+
+	fl = fopen("lastindex", FILE_ACCESS_MODES_RW);
+	if(fl == NULL) {
+	}
+	else {
+		fscanf(fl, "%d %d", &StartMsg, &LastDate);
+		fclose(fl);
+	}
+
+	if(StartMsg == 0) {
+		f = fopen(F_SEARCH_DB, FILE_ACCESS_MODES_CW);
+		if(f == NULL) {
+			printf("Error opening DB file\n");
+			exit(0);
+		}
+		fclose(f);
+		in = new CMessageSearcher(SEARCHER_INDEX_CREATE_NEW);
+	}
+	else in = new CMessageSearcher(SEARCHER_INDEX_CREATE_EXISTING);
+	if(in->errnum != SEARCHER_RETURN_ALLOK) {
+		printf("Searcher init = failed\n");
+		exit(0);
+	}
+
+	sm = (SMessage*)malloc(sizeof(SMessage)*READ_MESSAGE_HEADER);
+	in->indexed_word_count = 0;
+
+	f = fopen(F_MSGINDEX, FILE_ACCESS_MODES_R);
+	f1 = fopen(F_MSGBODY, FILE_ACCESS_MODES_R);
+	f2 = fopen(F_VINDEX, FILE_ACCESS_MODES_R);
+
+	if(f == NULL || f1 == NULL || f2 == NULL) {
+		printf("Error opening database files\n");
+		exit(0);
+	}
+
+	DWORD rr, idx;
+	char *mbody;
+	DWORD wc = 0;
+	DWORD tm = time(NULL);
+	printf("Indexing(starting from %ld), report format: NUM-SEC, NUM-processed mess, SEC-seconds last 100 mess were indexed", StartMsg);
+
+	if(fseek(f2, (StartMsg+1)*sizeof(DWORD), SEEK_SET) != 0) {
+		printf(" Invalid starting index\n");
+		exit(0);
+	}
+
+	start = time(NULL);
+	while(!feof(f2)) {
+
+		if(StartMsg >= StopIndex) {
+			printf("Stopped at index %ld (StopIndex)", StartMsg);
+			break;
+		}
+		
+		if(fread(&idx, 1, sizeof(DWORD), f2) != sizeof(DWORD)) {
+			break;
+		}
+		StartMsg++;
+
+		if(idx == 0xFFFFFFFF) continue;
+		
+		if(fseek(f, idx, SEEK_SET) != 0) {
+			continue;
+		}
+		rr = fread(sm, 1, sizeof(SMessage), f);
+		if(rr != sizeof(SMessage) && rr != 0) {
+			printf("Error reading %s\n", F_MSGINDEX);
+			exit(0);
+		}
+		wc++;
+		in->InsertMessageToIndex(sm->MessageHeader, sm->ViIndex);
+
+	//	fflush(stdout);
+		if((sm->Flag & MESSAGE_HAVE_BODY) != 0 && sm->msize > 2) {
+			DWORD readed;
+			mbody = (char*)malloc(sm->msize + 10);
+			if(fseek(f1, sm->MIndex, SEEK_SET) != 0) {
+				free(mbody);
+				continue;
+			}
+			if((readed = fread(mbody, 1, sm->msize + 2, f1)) < sm->msize) {
+				free(mbody);
+				continue;
+			}
+			mbody[readed] = 0;
+			if(sm->msize != 0 && *mbody == 0) {
+				char *ss = mbody;
+				ss++;
+				while(*ss) {
+					*(ss-1) = *(ss);
+					ss++;
+				}
+				*(ss-1) = *ss;
+			}
+			if(strlen(mbody) > 65000) {
+				printf("\nIncorrect DB format: Body of message %d is too long\n", sm->ViIndex);
+				exit(0);
+			}
+			in->InsertMessageToIndex(mbody, sm->ViIndex);
+			free(mbody);
+		}
+		if((wc % 100) == 0) {
+			now = time(NULL);
+		    printf("%ld-%d.", wc, start-now);
+			start = now;
+			fflush(stdout);
+		}
+	}
+	fclose(f);
+	fclose(f1);
+	fclose(f2);
+	printf("\nDone at %ld\nFlusing cache...", StartMsg);
+	DWORD iww = in->indexed_word_count;
+	delete in;
+
+	fl = fopen("lastindex", FILE_ACCESS_MODES_CW);
+	if(f != NULL) {
+		fprintf(fl, "%d %d", StartMsg, LastDate);
+		fclose(fl);
+	}
+
+	printf("\nFinished in %ld seconds, words indexed %ld\n", time(NULL) - tm, iww);
+	free(sm);
+	return 0;
+}
blob - /dev/null
blob + 8e6cd3beba265e752ff76c46179a9737d4529111 (mode 644)
--- /dev/null
+++ src/robot_workaround.cpp
@@ -0,0 +1,15 @@
+bool IsRobotNick(char *nick)  // code by ring0 & jetsys
+{
+	static char robot_rus[]="ЁюсюЄ-ьєЁчюыюу-";
+	static char robot_lat[]="poсoЄ-ьypчoыoу-";
+	if(!nick) 
+		return false;
+	for(int i = 0; i <= 14; i++) {
+		if(
+			nick[i] != robot_rus[i] && 
+			nick[i] != robot_lat[i]
+			) 
+			return false;
+	}
+	return true;
+}
\ No newline at end of file
blob - /dev/null
blob + 397cee55915c78740956ef1a620eeae7d505699a (mode 644)
--- /dev/null
+++ src/robot_workaround.h
@@ -0,0 +1 @@
+bool IsRobotNick(char *nick);
\ No newline at end of file
blob - /dev/null
blob + ce07edc994ba203573b7caed63107dcda2220b14 (mode 644)
--- /dev/null
+++ src/searcher.cpp
@@ -0,0 +1,650 @@
+/***************************************************************************
+                          searcher.cpp  -  message search support
+                             -------------------
+    begin                : Wed Mar 14 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "searcher.h"
+
+#define SEARCHER_REALLOC_ALLSUBSTRINGS_MULTI 10
+#define SEARCHER_MAX_WORD_LENGTH 20
+
+#define sr_lock_file()		{lock_file(f);}
+#define sr_unlock_file()	{unlock_file(f);}
+#define sr_unlock_and_db_error()	{unlock_file(f); errnum = SEARCHER_RETURN_DB_ERROR; return SEARCHER_RETURN_DB_ERROR;}
+#define sr_db_error()	{errnum = SEARCHER_RETURN_DB_ERROR; return SEARCHER_RETURN_DB_ERROR;}
+#define sr_db_error1()	{errnum = SEARCHER_RETURN_DB_ERROR; return NULL;}
+
+/* toupper string using CP1251
+ */
+char* toupperstr(char *s)
+{
+	if(s == NULL) return s;
+	register DWORD k = (DWORD)strlen(s);
+	for(register DWORD i = 0; i < k; i++) {
+		if(s[i] >= 'р' && s[i] <= ' ') {
+			s[i] -= ('р' - '└');
+		}
+		else {
+			if(!(s[i] >= '└' && s[i] <= '▀'))
+				s[i] = (char)toupper((unsigned char)s[i]);
+		}
+	}
+	return s;
+}
+
+/***************************
+ * fast quick sort algorithm
+ */
+#define QSORT_MAXSTACK (sizeof(DWORD)*200)
+
+void inline swap(DWORD *a, DWORD *b)
+{
+	register DWORD t=*a;
+	*a=*b;
+	*b = t;
+}
+
+int inline compar(const void *a, const void *b) { return *(DWORD *)a - *(DWORD *)b; }
+
+void inline mqsort(void *base, size_t nmemb) {
+    void *lbStack[QSORT_MAXSTACK], *ubStack[QSORT_MAXSTACK];
+    int sp;
+    DWORD offset;
+    lbStack[0] = (char *)base;
+    ubStack[0] = (char *)base + (nmemb-1)*sizeof(DWORD);
+    for (sp = 0; sp >= 0; sp--) {
+        char *lb, *ub, *m;
+        char *P, *i, *j;
+
+        lb = (char*)lbStack[sp];
+        ub = (char*)ubStack[sp];
+
+        while (lb < ub) {
+            offset = DWORD((ub - lb) >> 1);
+            P = lb + offset - offset % sizeof(DWORD);
+            swap( (DWORD*)lb, (DWORD*)P);
+
+            i = lb + sizeof(DWORD);
+            j = ub;
+            for(;;) {
+				while (i < j && compar(lb, i) > 0) i += sizeof(DWORD);
+                while (j >= i && compar(j, lb) > 0) j -= sizeof(DWORD);
+                if (i >= j) break;
+                swap((DWORD*)i, (DWORD*)j);
+                j -= sizeof(DWORD);
+                i += sizeof(DWORD);
+            }
+
+            swap((DWORD*)lb, (DWORD*)j);
+            m = j;
+
+            if (m - lb <= ub - m) {
+                if (m + sizeof(DWORD) < ub) {
+                    lbStack[sp] = m + sizeof(DWORD);
+                    ubStack[sp++] = ub;
+                }
+                ub = m - sizeof(DWORD);
+            }
+			else {
+                if (m - sizeof(DWORD) > lb) {
+                    lbStack[sp] = lb; 
+                    ubStack[sp++] = m - sizeof(DWORD);
+                }
+                lb = m + sizeof(DWORD);
+            }
+        }
+    }
+}
+
+/* Linear join two sorted arrays
+ * find an equals element in arrays buf1, buf2 and store them to rbuf
+ * return count of the found equal elements
+ */
+DWORD inline join_sorted(DWORD *buf1, DWORD c1, DWORD *buf2, DWORD c2, DWORD **rbuf)
+{
+	DWORD c = 0, minc;
+	DWORD p1 = 0, p2 = 0;
+	if(c1 > c2) minc = c2; else minc = c1;
+	*rbuf = (DWORD*)malloc(minc*sizeof(DWORD));
+	
+	for(;;) {
+		if(buf1[p1] > buf2[p2]) {
+			if(p2 < (c2 - 1)) p2++;
+			else break;
+		}
+		else {
+			if(buf1[p1] < buf2[p2]) {
+				if(p1 < (c1 - 1)) p1++;
+				else break;
+			}
+			else {
+				(*rbuf)[c] = buf1[p1];
+				c++;
+				if(p2 < (c2 - 1)) p2++;
+				else {
+					if(p1 < (c1 - 1)) p1++;
+					else break;
+				}
+			}
+		}
+	}
+
+	if(c != 0) *rbuf = (DWORD*)realloc(*rbuf, c*sizeof(DWORD));
+	else {
+		free(*rbuf);
+		*rbuf = NULL;
+	}
+	return c;
+}
+
+/***************************
+ * CMessageSearcher class 
+ */
+
+/* generate all substrings of string s with length > SEARCHER_MIN_WORD
+ * return number of substrings in resulting string *res, resulting string *res
+ * ended with 0x00 0x00 at the end
+ */
+int CMessageSearcher::GetAllSubstrings(char *s, char **res)
+{
+	DWORD a, b, i, j, mlen, len, inc;
+	DWORD wc = 0;
+	b = a = (DWORD)strlen(s);
+	inc = mlen = SEARCHER_REALLOC_ALLSUBSTRINGS_MULTI*b;
+	*res = (char*)malloc(mlen);
+	if(a <= SEARCHER_MIN_WORD) {
+		strcpy(*res, s);
+		*res = (char*)realloc(*res, b + 1);
+		return 1;
+	}
+	a -= SEARCHER_MIN_WORD;
+	len = 0;
+	DWORD r = 0;
+	for(i = 0; i <= a; i++) {
+		for(j = i + SEARCHER_MIN_WORD - 1; j < b; j++) {
+			char tmp = *(s + j + 1);
+			*(s + j + 1) = 0;
+			if(j - i + 1 +len >= mlen) {
+				mlen = mlen + inc;
+				*res = (char*)realloc(*res, mlen);
+			}
+			wc++;
+			strcpy((*res) + r, s +  i);
+			r += j-i+2;
+			len += j-i+2;
+			*(s + j + 1) = tmp;
+		}
+	}
+	(*res)[r] = 0;
+	*res = (char*)realloc(*res, len + 1);
+	return wc;
+}
+
+CMessageSearcher::CMessageSearcher(DWORD flags)
+{
+	DWORD i;
+	srch_str = NULL;
+	srch_str_len = 0;
+	SI = new CIndexFile(F_SEARCH_INDEX, flags, (WORD)strlen(SEARCHER_SYMBOLS_TABLE),
+					SEARCHER_SYMBOLS_TABLE, SEARCHER_INDEX_LENGTH);
+	f = NULL;
+	symtbl = NULL;
+	indexed_word_count = 0;
+	if(SI->errnum != INDEXFILE_ERROR_ALLOK) {
+		delete SI;
+		SI = NULL;
+		errnum = SEARCHER_RETURN_DB_ERROR;
+		return;
+	}
+	if((f = wcfopen(F_SEARCH_DB,
+					(flags & SEARCHER_INDEX_CREATE_NEW) ? FILE_ACCESS_MODES_CW :
+					FILE_ACCESS_MODES_RW)) == NULL &&
+		(f = wcfopen(F_SEARCH_DB,
+					(flags & SEARCHER_INDEX_CREATE_EXISTING) ? FILE_ACCESS_MODES_CW :
+					FILE_ACCESS_MODES_RW)) == NULL
+	  )
+	{
+		delete SI;
+		SI = NULL;
+		errnum = SEARCHER_RETURN_DB_ERROR;
+		return;
+	}
+	symtbl = (char*)malloc(SEARCHER_MAX_CHARACTER_CODE);
+	if(symtbl == NULL) {
+		delete SI;
+		SI = NULL;
+		errnum = SEARCHER_RETURN_DB_ERROR;
+		return;
+	}
+	for(i = 0; i < SEARCHER_MAX_CHARACTER_CODE; i++)
+		symtbl[i] = 0;
+
+	for(i = 0; i < strlen(SEARCHER_SYMBOLS_TABLE); i++) {
+		symtbl[(unsigned char)SEARCHER_SYMBOLS_TABLE[i]] = 1;
+	}
+	errnum = SEARCHER_RETURN_ALLOK;
+}
+
+CMessageSearcher::~CMessageSearcher()
+{
+	if(SI != NULL) delete SI;
+	if(symtbl != NULL) free(symtbl);
+	if(srch_str != NULL) free(srch_str);
+	if(f != NULL) wcfclose(f);
+}
+
+/* insert word [word] with message index [mid] to search index
+ * return SEARCHER_RETURN_ALLOK if successfull, otherwise error code returned
+ */
+
+//int CMessageSearcher::InsertWordToIndex(char *word, DWORD mid)
+//{
+//	SSearcherHStruct sb, sb1, sv_sb;
+//	DWORD idx, dberr, curmalloc, pos_notfound, svpos;
+//	DWORD *buf;
+//
+//
+//	indexed_word_count++;
+//
+//	if((dberr = SI->GetIndexByWord(word, &idx, NULL)) == INDEXFILE_ERROR_INDEX_NOT_EXIST) {
+//		/* create new index */
+//		/********* lock f *********/
+//		sr_lock_file();
+//
+//		if(wcfseek(f, 0, SEEK_END) != 0) sr_unlock_and_db_error();
+//
+//		idx = wcftell(f);
+//
+//		/* tune sb1 - new block header */
+//		sb1.prev = 0xFFFFFFFF;
+//		sb1.count = SEARCHER_NEW_CLUSTER_BLOCK_SIZE;
+//		sb1.used = 1;
+//
+//		if(!fCheckedWrite(&sb1, sizeof(sb), f)) sr_unlock_and_db_error();
+//		buf = (DWORD*)malloc(sizeof(DWORD)*SEARCHER_NEW_CLUSTER_BLOCK_SIZE);
+//		if(buf == NULL) sr_unlock_and_db_error();
+//		buf[0] = mid;
+//		for(register DWORD i = 1; i < SEARCHER_NEW_CLUSTER_BLOCK_SIZE; i++) buf[i] = 0;
+//		if(!fCheckedWrite(buf, sizeof(DWORD)*SEARCHER_NEW_CLUSTER_BLOCK_SIZE, f)) {
+//			free(buf);
+//			sr_unlock_and_db_error();
+//		}
+//		free(buf);
+//
+//		if((dberr = SI->PutIndexByWord(word, idx)) != INDEXFILE_ERROR_ALLOK)
+//			sr_unlock_and_db_error();
+//
+//		goto Unlock_End;
+//	}
+//	if(dberr != INDEXFILE_ERROR_ALLOK)
+//		sr_db_error();
+//
+//	/* add index */
+//	sb.prev = idx;
+//
+//	if((buf = (DWORD*)malloc(sizeof(DWORD)*SEARCHER_NEW_CLUSTER_BLOCK_SIZE)) == NULL) sr_db_error();
+//	curmalloc = SEARCHER_NEW_CLUSTER_BLOCK_SIZE;
+//
+//	/********* lock f *********/
+//	sr_lock_file();
+//
+//	pos_notfound = 1;
+//
+//	if(sb.prev != 0xFFFFFFFF){
+//		if(wcfseek(f, sb.Next, SEEK_SET) != 0) sr_unlock_and_db_error();
+//
+//		idx = sb.prev;
+//
+//		if(!fCheckedRead(&sb, sizeof(SSearcherHStruct), f))
+//			sr_unlock_and_db_error();
+//
+//		/* is block to long ? */
+//		if(sb.used > curmalloc) {
+//			buf = (DWORD*)realloc(buf, sb.used*sizeof(DWORD));
+//			curmalloc = sb.count;
+//		}
+//
+//		if(!fCheckedRead(buf, sizeof(DWORD)*sb.used, f)) sr_unlock_and_db_error();
+//
+//		for(register DWORD i = 0; i < sb.used; i++) {
+//			if(buf[i] == mid) {
+//				/* already exist ! shouldn't add again */
+//				free(buf);
+//				goto Unlock_End;
+//			}
+//		}
+//
+//		if(sb.used < sb.count && pos_notfound) {
+//			/* save first usefull block */
+//			pos_notfound = 0;
+//			sv_sb = sb;
+//			svpos = idx;
+//		}
+//	}
+//
+//	free(buf);
+//
+//	if(pos_notfound == 1) {
+//		/* add new block */
+//		if(wcfseek(f, 0, SEEK_END) != 0) sr_unlock_and_db_error();
+//		sb.Next = wcftell(f);
+//
+//		/* tune sb1 - new block header */
+//		sb1.Next = 0xFFFFFFFF;
+//		sb1.count = SEARCHER_NEW_CLUSTER_BLOCK_SIZE;
+//		sb1.used = 1;
+//
+//		/* save new cluster block */
+//		if(!fCheckedWrite(&sb1, sizeof(sb), f)) sr_unlock_and_db_error();
+//		buf = (DWORD*)malloc(sizeof(DWORD)*SEARCHER_NEW_CLUSTER_BLOCK_SIZE);
+//		if(buf == NULL) sr_unlock_and_db_error();
+//		buf[0] = mid;
+//		for(register DWORD i = 1; i < SEARCHER_NEW_CLUSTER_BLOCK_SIZE; i++) buf[i] = 0;
+//		if(!fCheckedWrite(buf, sizeof(DWORD)*SEARCHER_NEW_CLUSTER_BLOCK_SIZE, f)) {
+//			free(buf);
+//			sr_unlock_and_db_error();
+//		}
+//		free(buf);
+//		if(wcfseek(f, idx, SEEK_SET) != 0) sr_unlock_and_db_error();
+//		if(!fCheckedWrite(&sb, sizeof(sb), f)) sr_unlock_and_db_error();
+//	}
+//	else {
+//		/* place for add found */
+//		sv_sb.used++;
+//
+//		if(wcfseek(f, svpos, SEEK_SET) != 0) sr_unlock_and_db_error();
+//
+//		if(!fCheckedWrite(&sv_sb, sizeof(sv_sb), f)) sr_unlock_and_db_error();
+//
+//		if(wcfseek(f, svpos + sizeof(sv_sb) + (sv_sb.used - 1)*sizeof(mid), SEEK_SET) != 0)
+//			sr_unlock_and_db_error();
+//		if(!fCheckedWrite(&mid, sizeof(mid), f))  sr_unlock_and_db_error();
+//	}
+//
+//Unlock_End:
+//	sr_unlock_file();
+//	/****** unlock f ******/
+//
+//	errnum = SEARCHER_RETURN_ALLOK;
+//	return SEARCHER_RETURN_ALLOK;
+//}
+
+/*
+ * return 1 if successfull otherwise zero returned
+ */
+/* Function create new block for storing references to messages(blocks, clusters, etc.) if bi = 0xFFFFFFF
+ * and put to new block message with CMessageSearcher::AddingMId
+ * return Id of created block or 0xFFFFFFFF if an error occured
+ */
+/*DWORD CMessageSearcher::AllocRefBlock()*/
+/*DWORD CMessageSearcher::AddMessageToRefBlock(DWORD bi)*/
+/*  changed, get last block, checking last MId, adding, retunrnig block address   */
+
+
+DWORD CMessageSearcher::AddMessageToRefBlock(DWORD bi)
+{
+	SSearcherHStruct sb;
+	DWORD buf[SEARCHER_NEW_CLUSTER_BLOCK_SIZE*SEARCHER_MAX_CONTIGIOUS_CLUSTERS];
+	bool add_new = 1;
+	// we just have found out that there is an existing block for this word
+	// so we should only add new message index
+
+	if (bi != INDEXFILE_NO_INDEX){
+		if(wcfseek(f, bi, SEEK_SET) != 0) goto Ret_Error;
+
+		if(!fCheckedRead(&sb, sizeof(SSearcherHStruct), f))
+			goto Ret_Error;
+
+		// is block to long ?
+		if(sb.used > SEARCHER_NEW_CLUSTER_BLOCK_SIZE*SEARCHER_MAX_CONTIGIOUS_CLUSTERS) {
+			// ASSERTION HERE - we do not support such large blocks
+			goto Ret_Error;
+		}
+
+		if(!fCheckedRead(buf, sizeof(DWORD)*sb.used, f))
+			goto Ret_Error;
+
+		// check last id
+		// AlexBi: If we are having full block here it's not bad idea to check through it
+		for(register DWORD i = 0; i < sb.used; i++) {
+			if(buf[i] == AddingMId) {
+				// already exist ! shouldn't add again
+				goto Ret_Ok;
+			}
+		}
+
+		if(sb.used < sb.count) {
+			// save first usefull block
+			sb.used++;
+			// update block header
+			if(wcfseek(f, bi, SEEK_SET) != 0) goto Ret_Error;
+			if(!fCheckedWrite(&sb, sizeof(sb), f)) goto Ret_Error;
+	
+			// update block data
+			if(wcfseek(f, bi + sizeof(sb) + (sb.used - 1)*sizeof(AddingMId), SEEK_SET) != 0)
+				goto Ret_Error;
+			if(!fCheckedWrite(&AddingMId, sizeof(AddingMId), f))  goto Ret_Error;
+			add_new = 0;
+		}
+	}
+	if(add_new) {
+		// add new block
+	
+		/* tune sb - new block header */
+		sb.prev = bi;
+		sb.count = SEARCHER_NEW_CLUSTER_BLOCK_SIZE;
+		sb.used = 1;
+		
+		//get place
+		if(wcfseek(f, 0, SEEK_END) != 0) goto Ret_Error;
+		bi = wcftell(f);
+
+		// save new block header
+		if(!fCheckedWrite(&sb, sizeof(sb), f)) goto Ret_Error;
+
+		// create new block data
+		memset((void*)(&buf), 0, sizeof(DWORD)*SEARCHER_NEW_CLUSTER_BLOCK_SIZE);
+		buf[0] = AddingMId;
+		// save new block data
+		if(!fCheckedWrite(buf, sizeof(DWORD)*SEARCHER_NEW_CLUSTER_BLOCK_SIZE, f)) {
+			goto Ret_Error;
+		}
+	}
+Ret_Ok:
+	//return current last block 
+	return bi;
+Ret_Error:
+	return 0;
+}
+
+/* insert word [word] and subwords begining with [word] (lenght from 
+ * SEARCHER_MIN_WORD to [word]) with message index [mid] to search index
+ * return SEARCHER_RETURN_ALLOK if successfull, otherwise error code returned
+ */
+int CMessageSearcher::InsertWordWithSubwordsToIndex(char *word, DWORD mid)
+{
+	indexed_word_count++;
+
+	// create new index 
+	//********* lock f **********/
+	sr_lock_file();
+
+	// We have already allocated a new block if we'll need it later, so continue adding
+	// the word. Later, if we find out that do not need this block we simply skip creation step.
+	// this is not optimal realization, and later we should use a procedure varables.
+	// Then we should call PutOrGetIndexByWordAssoc()
+
+	AddingMId = mid;
+	if(SI->PutOrGetIndexByWordAssoc(word, SEARCHER_MIN_WORD - 1, this) != INDEXFILE_ERROR_ALLOK)
+		sr_unlock_and_db_error();
+
+	sr_unlock_file();
+	/****** unlock f ******/
+	
+	errnum = SEARCHER_RETURN_ALLOK;
+	return SEARCHER_RETURN_ALLOK;
+}
+
+
+/* insert message with VIndex = mid to index
+ * return SEARCHER_RETURN_ALLOK if successfull, otherwise error code returned
+ */
+int CMessageSearcher::InsertMessageToIndex(char *body, DWORD mid)
+{
+	DWORD i, rr;
+	toupperstr(body);
+	do {
+		i = 0;
+		while(body[i] != 0 && symtbl[(unsigned char)body[i]] == 1 && i < SEARCHER_MAX_WORD_LENGTH) i++;
+		if(i >= SEARCHER_MIN_WORD) {
+			char x = body[i];
+			body[i] = 0;
+
+			DWORD a = i - SEARCHER_MIN_WORD;
+			for(register DWORD k = 0; k <= a; k++) {
+				rr = InsertWordWithSubwordsToIndex(body + k, mid);
+				if(rr != SEARCHER_RETURN_ALLOK) return rr;
+			}
+
+			/*DWORD *xx;
+			DWORD cnt;
+			if((xx = SearchMessagesByPattern(body + 1, &cnt)) != 0) {
+				free(xx);
+			}*/
+
+			body[i] = x;
+		}
+		if(body[i] != 0) body += i + 1;
+		else body += i;
+
+	} while(*body != 0);
+	errnum = SEARCHER_RETURN_ALLOK;
+	return SEARCHER_RETURN_ALLOK;
+}
+
+DWORD* CMessageSearcher::SearchMessagesByWord(char *wmask, DWORD *count)
+{
+	DWORD cd;
+	int uniq;
+	SSearcherHStruct sb;
+	DWORD *buf;
+
+	*count = 0;
+
+	if((cd = SI->GetIndexByWord(wmask, &(sb.prev), &uniq)) != INDEXFILE_ERROR_ALLOK) {
+		switch(cd) {
+		case INDEXFILE_ERROR_INVALID_WORD:
+			errnum = SEARCHER_RETURN_INVALID_WORD;
+			return NULL;
+			break;
+		case INDEXFILE_ERROR_INDEX_NOT_EXIST:
+			errnum = SEARCHER_RETURN_WORD_NOT_FOUND;
+			return NULL;
+			break;
+		default:
+			errnum = SEARCHER_RETURN_DB_ERROR;
+			return NULL;
+		}
+	}
+
+	buf = (DWORD*)malloc(1);
+	while(sb.prev != 0xFFFFFFFF) {
+		if(wcfseek(f, sb.prev, SEEK_SET) != 0) {
+			free(buf);
+			sr_db_error1();
+		}
+		if(!fCheckedRead(&sb, sizeof(sb), f)) {
+			free(buf);
+			sr_db_error1();
+		}
+		
+		buf = (DWORD*)realloc(buf, (*count)*sizeof(DWORD) +  sb.used*sizeof(DWORD) + 1);
+
+		if(!fCheckedRead(&(buf[*count]), sb.used*sizeof(DWORD), f)) {
+			free(buf);
+			sr_db_error1();
+		}
+		*count += sb.used;
+	}
+	errnum = SEARCHER_RETURN_ALLOK;
+	return buf;
+}
+
+DWORD* CMessageSearcher::SearchMessagesByPattern(char *wpat, DWORD *count)
+{
+	DWORD *buf, *res;
+	DWORD i, cnt, rescnt = 0;
+	*count = 0;
+	res = NULL;
+	
+	toupperstr(wpat);
+
+	if(srch_str == NULL) {
+		srch_str = (char*)malloc(1);
+		srch_str_len = 1;
+	}
+	srch_str[0] = 0;
+
+	do {
+		i = 0;
+		while(wpat[i] != 0 && symtbl[(unsigned char)wpat[i]] == 1) i++;
+		if(i >= SEARCHER_MIN_WORD) {
+			char x = wpat[i];
+			wpat[i] = 0;
+			if(srch_str_len <= (strlen(srch_str) + strlen(wpat) + 10)) {
+				srch_str = (char*)realloc(srch_str, (strlen(srch_str) + strlen(wpat) + 10));
+				srch_str_len = (DWORD)strlen(srch_str) + strlen(wpat) + 10;
+				/* first search ? */
+				if(res != NULL) {
+					strcat(srch_str, " & ");
+				}
+				else strcat(srch_str, " ");
+				strcat(srch_str, wpat);
+			}
+			buf = SearchMessagesByWord(wpat, &cnt);
+			wpat[i] = x;
+			if(errnum == SEARCHER_RETURN_ALLOK && buf == NULL)
+				errnum = SEARCHER_RETURN_WORD_NOT_FOUND;
+			switch(errnum) {
+
+			case SEARCHER_RETURN_WORD_NOT_FOUND:
+				if(res != NULL) free(res);
+				res = NULL;
+				*count = 0;
+				goto Finishing;
+
+			case SEARCHER_RETURN_ALLOK:
+				mqsort(buf, cnt);
+				if(res != NULL) {
+					DWORD *buf1;
+					rescnt = join_sorted(res, rescnt, buf, cnt, &buf1);
+					free(buf);
+					free(res);
+					res = buf1;
+				}
+				else {
+					res = buf;
+					rescnt = cnt;
+				}
+				break;
+
+			default:
+				errnum = SEARCHER_RETURN_DB_ERROR;
+				return NULL;
+			}
+		}
+		if(wpat[i] != 0) wpat += i + 1;
+		else wpat += i;
+	} while(*wpat != 0);
+	*count = rescnt;
+
+Finishing:
+	srch_str_len = (DWORD)strlen(srch_str) + 1;
+	srch_str = (char*)realloc(srch_str, strlen(srch_str) + 1);
+	errnum = SEARCHER_RETURN_ALLOK;
+	return res;
+}
blob - /dev/null
blob + cb9d56e9a638dbaaa81dd61b8261e39da13d9c6e (mode 644)
--- /dev/null
+++ src/searcher.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+                          searcher.h  -  message search support
+                             -------------------
+    begin                : Wed Mar 14 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef SEARCHER_H_INCLUDED
+#define SEARCHER_H_INCLUDED
+
+#include "basetypes.h"
+#include "indexer.h"
+
+#define SEARCHER_INDEX_CREATE_NEW INDEXFILE_CREATE_NEW
+#define SEARCHER_INDEX_CREATE_EXISTING INDEXFILE_CREATE_EXISTING
+#define SEARCHER_SYMBOLS_TABLE "QWERTYUIOPASDFGHJKLZXCVBNM╔╓╙╩┼═├╪┘╟╒┌╘█┬└╧╨╬╦─╞▌▀╫╤╠╚╥▄┴▐и1234567890_&@!"
+#define SEARCHER_MAX_CHARACTER_CODE 256
+#define SEARCHER_INDEX_LENGTH	256
+#define SEARCHER_MIN_WORD		3
+
+/* searcher function error codes */
+#define SEARCHER_RETURN_ALLOK				0
+#define	SEARCHER_RETURN_ALREADY_EXIST		1
+#define SEARCHER_RETURN_DB_ERROR			2
+#define SEARCHER_RETURN_INVALID_WORD		3
+#define SEARCHER_RETURN_WORD_TOO_SHORT		4
+#define SEARCHER_RETURN_UNKNOWN_ERROR		5
+#define SEARCHER_RETURN_WORD_NOT_FOUND		6
+
+#define SEARCHER_NEW_CLUSTER_BLOCK_SIZE		25
+#define SEARCHER_MAX_CONTIGIOUS_CLUSTERS	20
+
+/* search cluster block header */
+struct SSearcherHStruct {
+	DWORD prev; // if no prev 0xFFFFFFFF
+	DWORD used;
+	DWORD count;
+};
+
+/* message searcher class */
+class CMessageSearcher
+{
+protected:
+	int init;
+	WCFILE *f;
+	int GetAllSubstrings(char *s, char **res);
+public:
+
+	DWORD errnum, indexed_word_count;
+	CIndexFile *SI;
+	char *symtbl;
+	char *srch_str;
+	DWORD srch_str_len;
+	CMessageSearcher(DWORD flags);
+	~CMessageSearcher();
+
+	//int insertwordtoindex(char *word, dword mid);
+	int InsertWordWithSubwordsToIndex(char *word, DWORD mid);
+	int InsertMessageToIndex(char *body, DWORD mid);
+	DWORD* SearchMessagesByWord(char *wmask, DWORD *count);
+	DWORD* SearchMessagesByPattern(char *wpat, DWORD *count);
+
+	DWORD AddMessageToRefBlock(DWORD bi =INDEXFILE_NO_INDEX);
+	DWORD AddingMId;
+};
+
+#endif
blob - /dev/null
blob + 5f748c6328947dcc7c4b28d80b913c495174a4ff (mode 644)
--- /dev/null
+++ src/security.cpp
@@ -0,0 +1,410 @@
+/***************************************************************************
+                          security.cpp  -  antispam&SSL and other secur.
+                             -------------------
+    begin                : Tue Apr 3 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "security.h"
+#include "error.h"
+#include "messages.h"
+
+/* find out is IP and Msg in buf
+ * also find latest date of record in list
+ * if ip found it returns index of it in buf, otherwise -1 returned
+ */
+int CheckForIpAndMsgInQueue(DWORD ip, DWORD Msg, SReadQueue *buf, int n, int &Alatest)
+{
+	Alatest = 0; // Max time
+
+	for(int i = 0; i < n; i++)
+	{
+		// also find latest date
+		if(buf[Alatest].Date > buf[i].Date) Alatest = i;
+		
+		if(buf[i].IP == ip && buf[i].MsgIndex == Msg)
+		{
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+/* */
+int CheckReadValidity(DWORD IP, DWORD MsgIndex)
+{
+	WCFILE *f;
+	SReadQueue buf[READQUEUE_LENGTH + 1];
+	time_t t = time(NULL);
+	int x, Alatest;
+
+	if((f = wcfopen(F_ANTISPAM, FILE_ACCESS_MODES_RW)) == NULL)
+	{
+		if((f = wcfopen(F_ANTISPAM, FILE_ACCESS_MODES_CW)) != NULL)
+		{
+			// create and save post list
+
+			lock_file(f);
+
+			SSpamQueue *mbuf = (SSpamQueue*)malloc(SPAMQUEUE_LENGTH*sizeof(SSpamQueue) + 1);
+			memset(mbuf, 0, sizeof(SSpamQueue)*SPAMQUEUE_LENGTH);
+
+			if(!fCheckedWrite(mbuf, SPAMQUEUE_LENGTH*sizeof(SSpamQueue), f)) {
+				unlock_file(f);
+				wcfclose(f);
+				printhtmlerror();
+			}
+			free(mbuf);
+
+			// create and save read list
+
+			memset(buf, 0, sizeof(SReadQueue)*READQUEUE_LENGTH);
+
+			if(!fCheckedWrite(buf, READQUEUE_LENGTH*sizeof(SReadQueue), f)) {
+				unlock_file(f);
+				wcfclose(f);
+				printhtmlerror();
+			}
+
+			unlock_file(f);
+
+			wcfclose(f);
+
+			if((f = wcfopen(F_ANTISPAM, FILE_ACCESS_MODES_RW)) == NULL)
+				printhtmlerror();
+		}
+		else printhtmlerror();
+	}
+
+	lock_file(f);
+
+	if(wcfseek(f, READQUEUE_PREFIX, SEEK_SET) != 0) {
+		unlock_file(f);
+		wcfclose(f);
+		printhtmlerror();
+	}
+
+	if(!fCheckedRead(buf, READQUEUE_LENGTH*sizeof(SReadQueue), f)) {
+		unlock_file(f);
+		wcfclose(f);
+		printhtmlerror();
+	}
+
+	if((x = CheckForIpAndMsgInQueue(IP, MsgIndex, buf, READQUEUE_LENGTH, Alatest)) != -1)
+	{
+		unlock_file(f);
+		wcfclose(f);
+		// return status = READ INVALID
+		return 0;
+	}
+
+	// update: delete entry with most early date
+	// and set our client information
+	buf[Alatest].IP = IP;
+	buf[Alatest].Date = t;
+	buf[Alatest].MsgIndex = MsgIndex;
+	
+	if(wcfseek(f, READQUEUE_PREFIX, SEEK_SET) != 0) {
+		unlock_file(f);
+		wcfclose(f);
+		printhtmlerror();
+	}
+	if(!fCheckedWrite(buf, READQUEUE_LENGTH*sizeof(SReadQueue), f)) {
+		unlock_file(f);
+		wcfclose(f);
+		printhtmlerror();
+	}
+	unlock_file(f);
+	wcfclose(f);
+	// return status - READ VALID
+	return 1;
+}
+
+/* find out is IP in buf
+ * if ip found it returns index of it in buf, otherwise -1 returned
+ */
+int CheckForIpInQueue(DWORD ip, SSpamQueue *buf, int n, int &Alatest)
+{
+	Alatest = 0; // Max time
+
+	for(int i = 0; i < n; i++)
+	{
+		// also find latest date
+		if(buf[Alatest].Date > buf[i].Date) Alatest = i;
+		
+		if(buf[i].IP == ip)
+		{
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+
+int MarkPostfromIPInvalid(DWORD IP, int TimeInterval)
+{
+	int Alatest;
+	WCFILE *f;
+	time_t t = time(NULL);
+	SSpamQueue buf[SPAMQUEUE_LENGTH + 1];
+
+	if((f = wcfopen(F_ANTISPAM, FILE_ACCESS_MODES_RW)) == NULL)
+		printhtmlerror();
+
+	lock_file(f);
+	
+	if(!fCheckedRead(buf, SPAMQUEUE_LENGTH*sizeof(SSpamQueue), f))
+		printhtmlerror();
+
+	Alatest = 0; //	Max time
+
+	for(int i = 0; i < SPAMQUEUE_LENGTH; i++)
+	{
+		//	find earliest date
+		if(buf[Alatest].Date > buf[i].Date) Alatest = i;
+	}
+
+	// update: delete entry with most early date
+	buf[Alatest].IP = IP;
+	buf[Alatest].Date = t;
+
+	if(wcfseek(f, 0, SEEK_SET) != 0)
+		printhtmlerror();
+	if(!fCheckedWrite(buf, SPAMQUEUE_LENGTH*sizeof(SSpamQueue), f))
+		printhtmlerror();
+
+	unlock_file(f);
+	wcfclose(f);
+
+	return 0;
+}
+
+/* check if it valid enter of user with IP
+ * return 1 if valid, 0 otherwise
+ */
+int CheckPostfromIPValidity(DWORD IP, int TimeInterval)
+{
+	WCFILE *f;
+	SSpamQueue buf[SPAMQUEUE_LENGTH + 1];
+	time_t t = time(NULL);
+	int x, Alatest;
+
+	if((f = wcfopen(F_ANTISPAM, FILE_ACCESS_MODES_RW)) == NULL)
+	{
+		if((f = wcfopen(F_ANTISPAM, FILE_ACCESS_MODES_CW)) != NULL)
+		{
+			// create and save post list
+
+			lock_file(f);
+
+			memset(buf, 0, sizeof(SSpamQueue)*SPAMQUEUE_LENGTH);
+
+			if(!fCheckedWrite(buf, SPAMQUEUE_LENGTH*sizeof(SSpamQueue), f)) {
+				unlock_file(f);
+				wcfclose(f);
+				printhtmlerror();
+			}
+
+			// create and save read list
+
+			SReadQueue *mbuf = (SReadQueue*)malloc(READQUEUE_LENGTH*sizeof(SReadQueue) + 1);
+			memset(mbuf, 0, sizeof(SReadQueue)*READQUEUE_LENGTH);
+
+			if(!fCheckedWrite(mbuf, READQUEUE_LENGTH*sizeof(SReadQueue), f)) {
+				unlock_file(f);
+				wcfclose(f);
+				printhtmlerror();
+			}
+			free(mbuf);
+
+			unlock_file(f);
+
+			wcfclose(f);
+
+			return 1;
+		}
+		else printhtmlerror();
+	}
+	
+	lock_file(f);
+	
+	if(!fCheckedRead(buf, SPAMQUEUE_LENGTH*sizeof(SSpamQueue), f))
+		printhtmlerror();
+
+	unlock_file(f);
+	wcfclose(f);
+
+	if((x = CheckForIpInQueue(IP, buf, SPAMQUEUE_LENGTH, Alatest)) != -1)
+	{
+		if(buf[x].Date + TimeInterval > t && buf[x].Date < t )
+		{
+			// return status - POST INVALID
+			return 0;
+		}
+	}
+
+	// return status - POST VALID
+	return 1;
+}
+
+//  This code makes available Marsaglia's highly portable generator
+//  of uniformly distributed pseudo-random numbers.
+//
+//  The sequence of 24 bit pseudo-random numbers produced has a period
+//  of about 2**144, and has passed stringent statistical tests for
+//  randomness and independence.
+//
+//  Supplying a seed or seeds to init_rand(s1, s2) is optional.
+//
+//  The correspondence between pairs of seeds and generated sequences
+//  of pseudo-random numbers is many-to-one.
+//
+//  References:
+//      M G Harmon & T P Baker, ``An Ada Implementation of Marsaglia's
+//      "Universal" Random Number Generator'', Ada Letters, late 1987.
+//
+//      G Marsaglia, ``Toward a universal random number generator'',
+//      to appear in the Journal of the American Statistical Association.
+
+//  output values are in the range 0..2^(24)-1
+
+static const unsigned long  two_to_24     = 0x01000000;
+static const unsigned short state_size    =         97;
+
+static const unsigned short p             =        179;
+static const unsigned short pm1           =      p - 1;
+static const unsigned short q             =     p - 10;
+
+static const unsigned long init_c         =     362436;
+static const unsigned long cd             =    7654321;
+static const unsigned long cm             =   16777213;
+
+// The state of the generator is described by the following
+// variables
+
+static unsigned short  index_i;        //  [0..state_size-1]
+static unsigned short  index_j;        //  [0..state_size-1]
+static unsigned long   u[state_size];  //  the state array
+static unsigned long   c;
+static bool            init_done = false;
+
+// This procedure initialises the state table u for a lagged
+// Fibonacci sequence generator, filling it with random bits
+// from a small multiplicative congruential sequence.    The
+// auxilliaries c, index_i and index_j are also initialized.
+// The seeds are transformed into an initial state in such a
+// way that identical results are obtained on a wide variety
+// of machines.
+
+    // Return a value between 0 and size-1 inclusive.  This value
+    // will be anyint itself if possible, otherwise another value
+    // in the required interval.
+
+static unsigned short col(short anyint, unsigned short size)
+{
+	short i = anyint;
+	if(i < 0) i = - (i / 2);
+	while (i >= size) i = i / 2;
+	return i;
+}
+
+void init_rand(unsigned short seed_a, unsigned short seed_b)
+{
+	DWORD s,bit;
+	WORD ii,jj,kk,mm;	// [0..p-1]
+	WORD ll;			// [0..q-1]
+	short sd;
+
+	sd = col(seed_a, pm1 * pm1);
+	ii = 1 + sd / pm1; jj = 1 + sd % pm1;
+
+	sd = col(seed_b, pm1 * q);
+	kk = 1 + sd / pm1; ll = sd % q;
+
+	if (ii == 1 && jj == 1 && kk == 1)
+		ii = 2;
+
+    for(short ind = 0; ind < state_size; ind++)
+    {
+        s = 0; bit = 1;
+
+        do
+        {
+            mm = (((ii * jj) % p) * kk) % p;
+
+            ii = jj; jj = kk; kk = mm;
+
+            ll = (53 * ll + 1) % q;
+
+            if ((ll * mm) & 0x0020)
+                s += bit;
+
+            bit <<= 1;
+        } while(bit < two_to_24);
+
+        u [ind] = s;
+    }
+
+    index_i = state_size - 1; index_j = state_size / 3; c  = init_c;
+
+    init_done = true;
+}
+
+// Return uniformly distributed pseudo random numbers in the range
+// 0..2^(24)-1 inclusive. There are 2^24 possible return values.
+
+static DWORD rand24(void)
+{
+	DWORD temp;
+
+	if(!init_done)
+	{
+		temp = (DWORD)time(NULL);
+        init_rand((WORD)(temp >> 16), (WORD)temp);
+	}
+
+	c = (c < cd ? c + (cm - cd) : c - cd);
+
+	temp = (u[index_i] -= u[index_j]);
+
+	if(!index_i--)
+		index_i = state_size - 1;
+
+	if(!index_j--)
+		index_j = state_size - 1;
+
+	return (temp - c) & (two_to_24 - 1);
+}
+
+// Return uniformly distributed pseudo random number in the range
+// 0..2^(32)-1 inclusive. There are 2^32 possible return values.
+
+static BYTE buf[13];	// buffer for conversion from 24 to
+						// 32 bit output
+static unsigned short bno = 0;	// number of output values in buffer
+
+DWORD rand32(void)
+{
+	if(!bno)
+	{
+		for(unsigned short i = 0; i < 12; i += 3)
+			*(DWORD*)(buf + i) = rand24();
+		bno = 12;
+	}
+	bno -= 4;
+	return *(DWORD*)(buf + 8 - bno);
+}
+
+void MakeSHA(char *origstring, char *shastring)
+{
+// e	CSHA1 sha1;
+// e	sha1.Reset();
+// e	sha1.Update((UINT_8 *)origstring, strlen(origstring));
+// e	sha1.Final();
+// e	sha1.GetHash((UINT_8 *)shastring);
+}
+
blob - /dev/null
blob + 12562b3429d2c03692027f011f57ecbbb6229b44 (mode 644)
--- /dev/null
+++ src/security.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+                          security.h  -  description
+                             -------------------
+    begin                : Tue Apr 3 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef SECURITY_H_INCLUDED
+#define SECURITY_H_INCLUDED
+
+#include "basetypes.h"
+#include "sha1.h"
+
+// antispam codes
+#define POST_MSG		1
+#define REFRESH_INDEX	2
+#define READ_MSG		3
+
+#define SPAMQUEUE_PREFIX		 0
+#define SPAMQUEUE_LENGTH		60
+
+#define READQUEUE_PREFIX		60*sizeof(SSpamQueue)
+#define READQUEUE_LENGTH		60
+
+struct SSpamQueue
+{
+	DWORD IP;				// ip address
+	time_t Date;			// date
+};
+
+struct SReadQueue
+{
+	time_t Date;	// date
+	DWORD IP;		// IP-address
+	DWORD MsgIndex; // message index
+};
+
+int MarkPostfromIPInvalid(DWORD IP, int TimeInterval);
+int CheckPostfromIPValidity(DWORD IP, int TimeInterval);
+
+int CheckReadValidity(DWORD IP, DWORD MsgIndex);
+
+unsigned long rand32(void);
+
+void init_rand(unsigned short seed_a = 1991, unsigned short seed_b = 9880);
+
+void MakeSHA(char *origstring, char *shastring);
+
+#endif
blob - /dev/null
blob + 0352a759289e9e8697811a7c9e43471315b7bc37 (mode 644)
--- /dev/null
+++ src/sendmail.cpp
@@ -0,0 +1,279 @@
+/***************************************************************************
+                          sendmail.cpp  -  mail sending support
+                             -------------------
+    begin                : Mon Nov 11 2002
+    copyright            : (C) 2002 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "sendmail.h"
+#include "messages.h"
+#include "error.h"
+
+
+static unsigned char dtable[512];
+
+void buffer_new(struct buffer_st *b)
+{
+  b->length = 512;
+  b->data = (char *)malloc(sizeof(char)*(b->length));
+  b->data[0] = 0;
+  b->ptr = b->data;
+  b->offset = 0;
+}
+
+void buffer_add(struct buffer_st *b, char c)
+{
+  *(b->ptr++) = c;
+  b->offset++;
+  if (b->offset == b->length) {
+    b->length += 512;
+    b->data = (char *)realloc(b->data, b->length);
+    b->ptr = b->data + b->offset;
+  }
+}
+
+void buffer_end(struct buffer_st *b)
+{
+    b->data[b->offset++]= 0;
+    //b->data = (char *)realloc(b->data, b->offset++);
+  
+}
+
+void buffer_delete(struct buffer_st *b)
+{
+  free(b->data);
+  b->length = 0;
+  b->offset = 0;
+  b->ptr = NULL;
+  b->data = NULL;
+}
+
+
+
+
+void base64_encode(struct buffer_st *b, const char *source, int length)
+{
+  int i, hiteof = 0;
+  int offset = 0;
+  int olen;
+  
+  olen = 0;
+  
+  buffer_new(b);
+  
+  /*	Fill dtable with character encodings.  */
+  
+  for (i = 0; i < 26; i++) {
+    dtable[i] = 'A' + i;
+    dtable[26 + i] = 'a' + i;
+  }
+  for (i = 0; i < 10; i++) {
+    dtable[52 + i] = '0' + i;
+  }
+  dtable[62] = '+';
+  dtable[63] = '/';
+  
+  while (!hiteof) {
+    unsigned char igroup[3], ogroup[4];
+    int c, n;
+    
+    igroup[0] = igroup[1] = igroup[2] = 0;
+    for (n = 0; n < 3; n++) {
+      c = *(source++);
+      offset++;
+      if (offset > length) {
+	hiteof = 1;
+	break;
+      }
+      igroup[n] = (unsigned char) c;
+    }
+    if (n > 0) {
+      ogroup[0] = dtable[igroup[0] >> 2];
+      ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
+      ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
+      ogroup[3] = dtable[igroup[2] & 0x3F];
+      
+      /* Replace characters in output stream with "=" pad
+	 characters if fewer than three characters were
+	 read from the end of the input stream. */
+      
+      if (n < 3) {
+	ogroup[3] = '=';
+	if (n < 2) {
+	  ogroup[2] = '=';
+	}
+      }
+      for (i = 0; i < 4; i++) {
+	buffer_add(b, ogroup[i]);
+	//if (!(b->offset % 72)) {
+	//  buffer_add(b, '\r');
+	//  buffer_add(b, '\n');
+	//}
+      }
+    }
+  }
+   //buffer_add(b, '\r');
+  //buffer_add(b, '\n');
+ buffer_end(b);
+}
+
+
+
+#if  MA_TYPE == 1
+
+/* Store the address of HOSTNAME, internet-style, to WHERE.  First
+   check for it in the host list, and (if not found), use
+   ngethostbyname to get it.
+   Return 1 on successful finding of the hostname, 0 otherwise.  */
+int store_hostaddress(unsigned char *where, const char *hostname)
+{
+	unsigned long addr;
+	struct hostent *hptr;
+	struct in_addr in;
+
+	/* If the address is of the form d.d.d.d, there will be no trouble
+	   with it.  */
+	addr = (unsigned long)inet_addr(hostname);
+	/* If we have the numeric address, just store it.  */
+	if((int)addr != -1)
+	{
+		/* This works on both little and big endian architecture, as
+		   inet_addr returns the address in the proper order.  It
+		   appears to work on 64-bit machines too.  */
+		memcpy (where, &addr, 4);
+		return 1;
+	}
+	/* Since all else has failed, let's try gethostbyname().  Note that
+	   we use gethostbyname() rather than ngethostbyname(), because we
+	   *know* the address is not numerical. */
+	hptr = gethostbyname (hostname);
+	if (!hptr)
+		return 0;
+	/* Copy the address of the host to socket description.  */
+	memcpy(where, hptr->h_addr_list[0], hptr->h_length);
+	/* Now that we're here, we could as well cache the hostname for
+	   future use, as in realhost().  First, we have to look for it by
+	   address to know if it's already in the cache by another name.  */
+
+	/* Originally, we copied to in.s_addr, but it appears to be missing
+	   on some systems.  */
+	memcpy(&in, *hptr->h_addr_list, sizeof (in));
+	return 1;
+}
+
+/* Create an internet connection to HOSTNAME on PORT.  The created
+   socket will be stored to *SOCK.  */
+int make_connection(int *sock, char *hostname, unsigned short port)
+{
+	struct sockaddr_in sock_name;
+	/* struct hostent *hptr; */
+
+	/* Get internet address of the host.  We can do it either by calling
+	   ngethostbyname, or by calling store_hostaddress, from host.c.
+	   storehostaddress is better since it caches calls to
+	   gethostbyname. */
+	   
+#if 1
+	if(!store_hostaddress ((unsigned char *)&sock_name.sin_addr, hostname))
+		return 0;
+#else  /* never */
+	if(!(hptr = ngethostbyname (hostname)))
+		return 0;
+	// Copy the address of the host to socket description.
+	memcpy(&sock_name.sin_addr, hptr->h_addr, hptr->h_length);
+#endif /* never */
+
+	/* Set port and protocol */
+	sock_name.sin_family = AF_INET;
+	sock_name.sin_port = htons (port);
+
+	/* Make an internet socket, stream type.  */
+	if ((*sock = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+		return 0;
+
+	/* Connect the socket to the remote host. */
+	if(connect(*sock, (struct sockaddr *) &sock_name, sizeof (sock_name)))
+	{
+		return 0;
+    }
+
+	struct timeval tv;
+	tv.tv_sec = 3;
+	tv.tv_usec = 0;
+
+	if(setsockopt(*sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(timeval)) == -1)
+		return 0;
+	if(setsockopt(*sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(timeval)) == -1)
+		return 0;
+
+	return 1;
+}
+
+
+
+
+int wcSendMail(char *to, char *subj, char *body)
+{
+	int ssock;
+	int rc;
+	char sbuf[100000];
+	char rbuf[10000];
+
+	if(!make_connection(&ssock, MA_SENDER, 25))
+		return 0;
+	sprintf(sbuf, MAIL_SEND_HELO, MA_FROM, to);
+	
+	if(send(ssock, sbuf, strlen(sbuf), 0) != (int)strlen(sbuf))
+		return 0;
+
+#ifdef WIN32
+	Sleep(500);
+#else	//ifdef WIN32
+	sleep(1);
+#endif	//ifdef WIN32
+	rc = recv(ssock, rbuf, 9999, 0);
+
+	
+	buffer_st subj_base64;
+	base64_encode(&subj_base64, subj ,strlen(subj) );
+	
+	//print2log("body %s to %s", body, to);
+	sprintf(sbuf, MAIL_SEND_DATA, MA_FROM, to, subj_base64.data, body);
+	
+	
+	buffer_delete(&subj_base64);
+	
+	if(send(ssock, sbuf, strlen(sbuf), 0) != (int)strlen(sbuf))
+		return 0;
+	rc = recv(ssock, rbuf, 9999, 0);
+	
+#ifdef WIN32
+	Sleep(500);
+#else	//ifdef WIN32
+	sleep(1);
+#endif	//ifdef WIN32
+	shutdown(ssock, 2);
+	return 1;
+}
+
+#else
+
+int wcSendMail(char *to, char *subj, char *body)
+{
+    
+	struct buffer_st subj_base64;
+	base64_encode(&subj_base64, subj, strlen(subj));
+	
+	FILE* MA_SEND;
+	MA_SEND=popen(MA_SENDER, FILE_ACCESS_MODES_RW);
+	fprintf(MA_SEND, MAIL_SEND_DATA, MA_FROM, to, subj_base64.data, body);
+	pclose(MA_SEND);
+ 	
+	buffer_delete(&subj_base64);
+	
+	return 1;
+}
+
+
+#endif
blob - /dev/null
blob + edd55e6503c7bb925d30ee64838a778f88529c68 (mode 644)
--- /dev/null
+++ src/sendmail.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+                          sendmail.h  -  mail sending support include
+                             -------------------
+    begin                : Wed Jun 13 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef SENDMAIL_H_INCLUDED
+#define SENDMAIL_H_INCLUDED
+
+#include "basetypes.h"
+#include "messages.h"
+// from base64.h
+
+#define MAIL_SEND_HELO "HELO localhost\r\nMAIL FROM: <%s>\r\nRCPT TO: <%s>\r\nDATA\r\n"
+#define MAIL_SEND_DATA "From: <%s>\r\nTo: <%s>\r\nSubject:=?Windows-1251?B?%s?=\r\n"\
+        MAILACKN_HEADER  "%s" MAIL_SEND_SIGNING "\r\n.\r\nQuit\r\n"
+		
+int wcSendMail(char *to, char *subj, char *body);
+
+struct buffer_st {
+  char *data;
+  int length;
+  char *ptr;
+  int offset;
+};
+
+void buffer_new(struct buffer_st *b);
+void buffer_add(struct buffer_st *b, char c);
+void buffer_delete(struct buffer_st *b);
+
+void base64_encode(struct buffer_st *b, const char *source, int length);
+
+
+#endif
blob - /dev/null
blob + 76028761b3184581b794a2a9f08a546c10b7539e (mode 644)
--- /dev/null
+++ src/sha1.cpp
@@ -0,0 +1,281 @@
+/*
+	100% free public domain implementation of the SHA-1 algorithm
+	by Dominik Reichl <dominik.reichl@t-online.de>
+	Web: http://www.dominik-reichl.de/
+
+	Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
+	- You can set the endianness in your files, no need to modify the
+	  header file of the CSHA1 class any more
+	- Aligned data support
+	- Made support/compilation of the utility functions (ReportHash
+	  and HashFile) optional (useful, if bytes count, for example in
+	  embedded environments)
+
+	Version 1.5 - 2005-01-01
+	- 64-bit compiler compatibility added
+	- Made variable wiping optional (define SHA1_WIPE_VARIABLES)
+	- Removed unnecessary variable initializations
+	- ROL32 improvement for the Microsoft compiler (using _rotl)
+
+	======== Test Vectors (from FIPS PUB 180-1) ========
+
+	SHA1("abc") =
+		A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+
+	SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
+		84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+
+	SHA1(A million repetitions of "a") =
+		34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#include "sha1.h"
+
+#ifdef SHA1_UTILITY_FUNCTIONS
+#define SHA1_MAX_FILE_BUFFER 8000
+#endif
+
+// Rotate x bits to the left
+#ifndef ROL32
+#ifdef _MSC_VER
+#define ROL32(_val32, _nBits) _rotl(_val32, _nBits)
+#else
+#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))
+#endif
+#endif
+
+#ifdef SHA1_LITTLE_ENDIAN
+#define SHABLK0(i) (m_block->l[i] = \
+	(ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
+#else
+#define SHABLK0(i) (m_block->l[i])
+#endif
+
+#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \
+	^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
+
+// SHA-1 rounds
+#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
+#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
+#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }
+#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }
+#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }
+
+CSHA1::CSHA1()
+{
+	m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
+	Reset();
+}
+
+CSHA1::~CSHA1()
+{
+	Reset();
+}
+
+void CSHA1::Reset()
+{
+	// SHA1 initialization constants
+	m_state[0] = 0x67452301;
+	m_state[1] = 0xEFCDAB89;
+	m_state[2] = 0x98BADCFE;
+	m_state[3] = 0x10325476;
+	m_state[4] = 0xC3D2E1F0;
+
+	m_count[0] = 0;
+	m_count[1] = 0;
+}
+
+void CSHA1::Transform(UINT_32 *state, UINT_8 *buffer)
+{
+	// Copy state[] to working vars
+	UINT_32 a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];
+
+	memcpy(m_block, buffer, 64);
+
+	// 4 rounds of 20 operations each. Loop unrolled.
+	_R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3);
+	_R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7);
+	_R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11);
+	_R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15);
+	_R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19);
+	_R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23);
+	_R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27);
+	_R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31);
+	_R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35);
+	_R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39);
+	_R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43);
+	_R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47);
+	_R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51);
+	_R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55);
+	_R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59);
+	_R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63);
+	_R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67);
+	_R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71);
+	_R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75);
+	_R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79);
+
+	// Add the working vars back into state
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+	state[4] += e;
+
+	// Wipe variables
+#ifdef SHA1_WIPE_VARIABLES
+	a = b = c = d = e = 0;
+#endif
+}
+
+// Use this function to hash in binary data and strings
+void CSHA1::Update(UINT_8 *data, UINT_32 len)
+{
+	UINT_32 i, j;
+
+	j = (m_count[0] >> 3) & 63;
+
+	if((m_count[0] += len << 3) < (len << 3)) m_count[1]++;
+
+	m_count[1] += (len >> 29);
+
+	if((j + len) > 63)
+	{
+		i = 64 - j;
+		memcpy(&m_buffer[j], data, i);
+		Transform(m_state, m_buffer);
+
+		for( ; i + 63 < len; i += 64) Transform(m_state, &data[i]);
+
+		j = 0;
+	}
+	else i = 0;
+
+	memcpy(&m_buffer[j], &data[i], len - i);
+}
+
+#ifdef SHA1_UTILITY_FUNCTIONS
+// Hash in file contents
+bool CSHA1::HashFile(char *szFileName)
+{
+	unsigned long ulFileSize, ulRest, ulBlocks;
+	unsigned long i;
+	UINT_8 uData[SHA1_MAX_FILE_BUFFER];
+	FILE *fIn;
+
+	if(szFileName == NULL) return false;
+
+	fIn = fopen(szFileName, "rb");
+	if(fIn == NULL) return false;
+
+	fseek(fIn, 0, SEEK_END);
+	ulFileSize = (unsigned long)ftell(fIn);
+	fseek(fIn, 0, SEEK_SET);
+
+	if(ulFileSize != 0)
+	{
+		ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER;
+		ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER;
+	}
+	else
+	{
+		ulBlocks = 0;
+		ulRest = 0;
+	}
+
+	for(i = 0; i < ulBlocks; i++)
+	{
+		fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn);
+		Update((UINT_8 *)uData, SHA1_MAX_FILE_BUFFER);
+	}
+
+	if(ulRest != 0)
+	{
+		fread(uData, 1, ulRest, fIn);
+		Update((UINT_8 *)uData, ulRest);
+	}
+
+	fclose(fIn); fIn = NULL;
+	return true;
+}
+#endif
+
+void CSHA1::Final()
+{
+	UINT_32 i;
+	UINT_8 finalcount[8];
+
+	for(i = 0; i < 8; i++)
+		finalcount[i] = (UINT_8)((m_count[((i >= 4) ? 0 : 1)]
+			>> ((3 - (i & 3)) * 8) ) & 255); // Endian independent
+
+	Update((UINT_8 *)"\200", 1);
+
+	while ((m_count[0] & 504) != 448)
+		Update((UINT_8 *)"\0", 1);
+
+	Update(finalcount, 8); // Cause a SHA1Transform()
+
+	for(i = 0; i < 20; i++)
+	{
+		m_digest[i] = (UINT_8)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255);
+	}
+
+	// Wipe variables for security reasons
+#ifdef SHA1_WIPE_VARIABLES
+	i = 0;
+	memset(m_buffer, 0, 64);
+	memset(m_state, 0, 20);
+	memset(m_count, 0, 8);
+	memset(finalcount, 0, 8);
+	Transform(m_state, m_buffer);
+#endif
+}
+
+#ifdef SHA1_UTILITY_FUNCTIONS
+// Get the final hash as a pre-formatted string
+void CSHA1::ReportHash(char *szReport, unsigned char uReportType)
+{
+	unsigned char i;
+	char szTemp[16];
+
+	if(szReport == NULL) return;
+
+	if(uReportType == REPORT_HEX)
+	{
+		sprintf(szTemp, "%02X", m_digest[0]);
+		strcat(szReport, szTemp);
+
+		for(i = 1; i < 20; i++)
+		{
+			sprintf(szTemp, " %02X", m_digest[i]);
+			strcat(szReport, szTemp);
+		}
+	}
+	else if(uReportType == REPORT_DIGIT)
+	{
+		sprintf(szTemp, "%u", m_digest[0]);
+		strcat(szReport, szTemp);
+
+		for(i = 1; i < 20; i++)
+		{
+			sprintf(szTemp, " %u", m_digest[i]);
+			strcat(szReport, szTemp);
+		}
+	}
+	else if(uReportType == REPORT_STRING)
+	{
+		for(i = 0; i < 20; i++)
+		{
+			sprintf(szTemp, "%c", m_digest[i]);
+			strcat(szReport, szTemp);
+		}
+	}
+	else strcpy(szReport, "Error: Unknown report type!");
+}
+#endif
+
+// Get the raw message digest
+void CSHA1::GetHash(UINT_8 *puDest)
+{
+	memcpy(puDest, m_digest, 20);
+}
blob - /dev/null
blob + 8b26b0e2f9e28478b856257ee822e303ea3619b0 (mode 644)
--- /dev/null
+++ src/sha1.h
@@ -0,0 +1,149 @@
+/*
+	100% free public domain implementation of the SHA-1 algorithm
+	by Dominik Reichl <dominik.reichl@t-online.de>
+	Web: http://www.dominik-reichl.de/
+
+	Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
+	- You can set the endianness in your files, no need to modify the
+	  header file of the CSHA1 class any more
+	- Aligned data support
+	- Made support/compilation of the utility functions (ReportHash
+	  and HashFile) optional (useful, if bytes count, for example in
+	  embedded environments)
+
+	Version 1.5 - 2005-01-01
+	- 64-bit compiler compatibility added
+	- Made variable wiping optional (define SHA1_WIPE_VARIABLES)
+	- Removed unnecessary variable initializations
+	- ROL32 improvement for the Microsoft compiler (using _rotl)
+
+	======== Test Vectors (from FIPS PUB 180-1) ========
+
+	SHA1("abc") =
+		A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+
+	SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
+		84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+
+	SHA1(A million repetitions of "a") =
+		34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#ifndef ___SHA1_HDR___
+#define ___SHA1_HDR___
+
+#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS)
+#define SHA1_UTILITY_FUNCTIONS
+#endif
+
+#include <memory.h> // Needed for memset and memcpy
+
+#ifdef SHA1_UTILITY_FUNCTIONS
+#include <stdio.h>  // Needed for file access and sprintf
+#include <string.h> // Needed for strcat and strcpy
+#endif
+
+#ifdef _MSC_VER
+#include <stdlib.h>
+#endif
+
+// You can define the endian mode in your files, without modifying the SHA1
+// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN
+// in your files, before including the SHA1.h header file. If you don't
+// define anything, the class defaults to little endian.
+
+#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN)
+#define SHA1_LITTLE_ENDIAN
+#endif
+
+// Same here. If you want variable wiping, #define SHA1_WIPE_VARIABLES, if
+// not, #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it
+// defaults to wiping.
+
+#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES)
+#define SHA1_WIPE_VARIABLES
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// Define 8- and 32-bit variables
+
+#ifndef UINT_32
+
+#ifdef _MSC_VER
+
+#define UINT_8  unsigned __int8
+#define UINT_32 unsigned __int32
+
+#else
+
+#define UINT_8 unsigned char
+
+#if (ULONG_MAX == 0xFFFFFFFF)
+#define UINT_32 unsigned long
+#else
+#define UINT_32 unsigned int
+#endif
+
+#endif
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// Declare SHA1 workspace
+
+typedef union
+{
+	UINT_8  c[64];
+	UINT_32 l[16];
+} SHA1_WORKSPACE_BLOCK;
+
+class CSHA1
+{
+public:
+#ifdef SHA1_UTILITY_FUNCTIONS
+	// Two different formats for ReportHash(...)
+	enum
+	{
+		REPORT_HEX = 0,
+		REPORT_DIGIT = 1,
+		REPORT_STRING = 2
+	};
+#endif
+
+	// Constructor and Destructor
+	CSHA1();
+	~CSHA1();
+
+	UINT_32 m_state[5];
+	UINT_32 m_count[2];
+	UINT_32 __reserved1[1];
+	UINT_8  m_buffer[64];
+	UINT_8  m_digest[20];
+	UINT_32 __reserved2[3];
+
+	void Reset();
+
+	// Update the hash value
+	void Update(UINT_8 *data, UINT_32 len);
+#ifdef SHA1_UTILITY_FUNCTIONS
+	bool HashFile(char *szFileName);
+#endif
+
+	// Finalize hash and report
+	void Final();
+
+	// Report functions: as pre-formatted and raw data
+#ifdef SHA1_UTILITY_FUNCTIONS
+	void ReportHash(char *szReport, unsigned char uReportType = REPORT_HEX);
+#endif
+	void GetHash(UINT_8 *puDest);
+
+private:
+	// Private SHA-1 transformation
+	void Transform(UINT_32 *state, UINT_8 *buffer);
+
+	// Member variables
+	UINT_8 m_workspace[64];
+	SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above
+};
+
+#endif
blob - /dev/null
blob + befcd21ebc13795dd2cce529e18e354baadbe969 (mode 644)
--- /dev/null
+++ src/speller.cpp
@@ -0,0 +1,340 @@
+/***************************************************************************
+                          speller.cpp  -  spell, ban, html checker
+                             -------------------
+    begin                : Mon Mar 19 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#include "basetypes.h"
+#include "speller.h"
+#include "error.h"
+#include "messages.h"
+#include "boardtags.h"
+
+#define TO_HEX(a) (a > 9 ? (a - 10) + 'A': a + '0')
+
+char* CodeHttpString(char *s, int allocmem)
+{
+	static char rs[SPELLER_INTERNAL_BUFFER_SIZE];
+	char *r, *rr;
+	DWORD sl = (DWORD)strlen(s);
+	if(allocmem) {
+		rr = r = (char*)malloc(3*sl + 10);
+	}
+	else {
+		if(sl > SPELLER_INTERNAL_BUFFER_SIZE/3) return NULL;
+		r = (char*)(&rs);
+		rr = r;
+	}
+	for(; *s != 0; s++) {	
+		if (*s >= 'A' && *s <='z') {
+			r[0] = *s;
+			r+=1;
+		} else {
+			r[0] = '%';
+			r[1] = TO_HEX( (((*s) &	0x00000000F0) >> 4)	);
+			r[2] = TO_HEX( ( (*s) & 0x000000000F) );
+			r+=3;
+		}
+	}
+	*r = 0;
+	return rr;
+}
+
+int IsMailCorrect(char *s)
+{
+	char *s1;
+	if(s == NULL) return 0;
+	if((s1 = strchr(s,'@')) == NULL) return 0;
+	if(strlen(s1) < 4) return 0;
+	if((s = strchr(s1,'.')) == NULL) return 0;
+	if(strlen(s) < 2) return 0;
+	return 1;
+}
+
+int FilterBadWords(char *s)
+{
+	FILE *f;
+	char dic[MAX_STRING];
+	char *sx, *ss = (char*)malloc(strlen(s) + 1);
+	int c;
+	int x = 0;
+	strcpy(ss, s);
+	ss = toupperstr(ss);
+	if((f = fopen(F_BADWORDS, FILE_ACCESS_MODES_R)) != NULL)
+	{
+		while(!feof(f)) {
+			dic[0] = 0;
+			fscanf(f,"%[^\n\10]", dic);
+
+			if(dic[0] != 0 && (dic[strlen(dic) - 1] == 13 || dic[strlen(dic) - 1] == 10))
+				dic[strlen(dic) - 1] = 0;
+
+			fscanf(f,"%c",&c);
+			toupperstr(dic);
+			while ((dic[0] != 0 ) && ((sx = strstr(ss, dic)) != NULL)) {
+				x = 1;
+				register DWORD tm = (DWORD)strlen(dic); 
+				for(register DWORD j = 0; j < tm; j++) {
+					s[sx - ss + j] = BAD_WORD_SYMBOL;
+					sx[j] = BAD_WORD_SYMBOL;
+				}
+			}
+		}
+	}
+	else print2log(LOG_WARN_UNABLETOOPENFILE, F_BADWORDS);
+	free(ss);
+	if(x) return 1;
+	else return 0;
+}
+
+// return filtered string with length not more than ml bytes (include '\0')
+char* FilterHTMLTags(char *s, WORD ml, int allocmem)
+{
+	char *os, *st;
+	static char *tb[SPELLER_INTERNAL_BUFFER_SIZE];
+	
+	while(*s == '\n') s++;
+	
+	int h = 0, k = 0;	
+	for(k = (int)strlen(s)-1; s[k]=='\n'; k--) h++;
+	k = (int)strlen(s);
+	s[k - h] = '\0';
+	if(allocmem)
+		st = (char*)malloc(4*k + 1);
+	else {
+		st = (char*)(&tb);
+	}
+	os = st;
+	while(*s != '\0' && st - os < ml) {
+		if(*s == '<') {
+			strcpy(st, "&lt;");
+			st+= 3;
+		}
+		else if(*s == '>') {
+			strcpy(st, "&gt;");
+			st+= 3;
+		}
+		else if(*s == '"') {
+			strcpy(st, "&quot;");
+			st+= 5;
+		}
+		else if(*s == '&') {
+			strcpy(st, "&amp;");
+			st+= 4;
+		}
+		else *st = *s;
+		s++;
+		st++;
+	}
+	if(st - os > ml) st-=4; // if it was overflow because of '<' or '>'
+	*st = '\0';
+	if(allocmem) os = (char *)realloc(os, strlen(os) +1);
+	return os;
+}
+
+// removing all white spaces from beginning and end of string
+char* FilterWhitespaces(char *s)
+{
+	while(isspace(((*s) & 0xff))) s++;
+	int h = 0, k = 0;
+	for(k = (int)strlen(s)-1; isspace((s[k] & 0xff)); k--) h++;
+	s[strlen(s) - h] = '\0';
+	return s;
+}
+
+// check if IP in mask
+// return 1 if successfull, 0 otherwise
+int CheckIPinSubnet(char *IP, char *mask)
+{
+	register DWORD i = 0, sl = (DWORD)strlen(mask);
+	if(sl == 0) return 1;
+	while(strlen(IP) > i && sl > i && IP[i] == mask[i]) {
+		i++;
+	}
+	if(sl == i && (mask[i - 1] == '.' || strlen(IP) == i)) return 1;
+	return 0;
+}
+
+void FilterMessageForPreview(char *s, char **dd)
+{
+	char *d;
+	if(!s) {
+		*dd = NULL;
+		return;
+	}
+	d = *dd = (char*)malloc(strlen(s) + 1);
+	while(*s != 0) {
+		if(*s != 10) {
+			*d = *s;
+			d++;
+		}
+		s++;
+	}
+	*d = *s;
+	*dd = (char*)realloc(*dd, d - (*dd) + 2);
+}
+
+int PrepareTextForPrint(char *msg, char **res, BYTE security, int flags, int spfl)
+{
+	DWORD tmp;
+	char *st;
+	int memalloc = 0;
+
+	*res = NULL;
+
+	if((SPELLER_FILTER_HTML & spfl) != 0) {
+		// if the message to small try to use internal buffers
+		if(strlen(msg) < SPELLER_INTERNAL_BUFFER_SIZE/2) {
+			st = FilterHTMLTags(msg, SPELLER_INTERNAL_BUFFER_SIZE - 10, 0);	// do not allocate memory
+		}
+		else {
+			st = FilterHTMLTags(msg, MAX_PARAMETERS_STRING);
+			memalloc = 1;
+		}
+	}
+	if(!st) return 0;
+
+	if((SPELLER_PARSE_TAGS & spfl) != 0) {
+		if(FilterBoardTags(st, res, security, MAX_PARAMETERS_STRING, flags, &tmp) == 0)
+		{
+			if(!memalloc) {
+				*res = (char*)malloc(strlen(st) + 1);
+				if(!(*res)) return 0;
+				strcpy(*res, st);
+			}
+			else *res = st;
+		}
+		else {
+			if(memalloc) free(st);
+		}
+	}
+	else {
+		if(!memalloc) {
+			*res = (char*)malloc(strlen(st) + 1);
+			if(!(*res)) return 0;
+			strcpy(*res, st);
+		}
+		else *res = st;
+	}
+
+	return 1;
+}
+
+int CheckSpellingBan(struct SMessage *mes, char **body, char **Reason,
+					 DWORD CFlags, DWORD *RetFlags, bool fRegged)
+{
+	FILE *f;
+	char ip[MAX_STRING];
+	char *reason = NULL;
+	char c, t;
+
+	char *st;
+	DWORD flg = 0;
+	if(FilterBoardTags(mes->MessageHeader, &st, mes->Security, MESSAGE_HEADER_LENGTH, BOARDTAGS_TAG_PREPARSE, RetFlags) == 0) {
+		return MSG_CHK_ERROR_NOMSGHEADER;
+	}
+	else {
+		strcpy(mes->MessageHeader, st);
+		free(st);
+	}
+
+	if(strlen(mes->MessageHeader) == 0 || strcmp(mes->MessageHeader, " ") == 0) return MSG_CHK_ERROR_NOMSGHEADER;
+	
+#if MSG_REQURED_BODY
+	if(strlen(body) == 0) return MSG_CHK_ERROR_NOMSGBODY;
+#endif
+	
+	// banned check + restriction check
+#if BANNED_CHECK
+	
+	reason = (char*)malloc(MAX_STRING);
+	if((f = fopen(F_BANNEDIP, FILE_ACCESS_MODES_R)) != NULL) {
+		while(!feof(f)) {
+			bool fProxy = false;
+			ip[0] = 0;
+			fscanf(f, "%[^ \n]", &ip);		// get ip
+			if(feof(f)) break;
+			fscanf(f, "%c", &c);			// skip " "
+			if(c == '\n') continue;
+			fscanf(f, "%c", &t);			// type
+			fscanf(f, "%c", &c);			// skip " "
+			fscanf(f, "%[^\n]", reason);	// ban reason
+			fscanf(f, "%c", &c);			// skip \n
+			if(CheckIPinSubnet(Cip, ip) &&
+				(t == '*' || (fProxy = ((t|0x20) == 'p' && !fRegged))))
+			{
+				if(fProxy)
+					strncat(reason, "[PROXY]", MAX_STRING - 1);
+					*Reason = reason;
+				return MSG_CHK_ERROR_BANNED;
+			}
+			if(CheckIPinSubnet(Cip, ip) && t == '=') {
+			    break;
+			}
+		}
+		fclose(f);
+	}
+	else print2log(LOG_WARN_UNABLETOOPENFILE, F_BANNEDIP);
+	free(reason);
+#endif
+	
+	/* HTML Filtering and WWWConf Tags parsing option */
+	
+	/* filter HTML in Headers */
+	if((CFlags & MSG_CHK_ALLOW_HTML) == 0) {
+		// HTML tags check and filtering (%lt, %gt)
+		char *st;
+		st = FilterHTMLTags(mes->MessageHeader, MESSAGE_HEADER_LENGTH - 1);
+		st = FilterWhitespaces(st);
+		strcpy(mes->MessageHeader, st);
+		free(st);
+		st = FilterHTMLTags(mes->AuthorName, AUTHOR_NAME_LENGTH - 1);
+		strcpy(mes->AuthorName, st);
+		free(st);
+	}
+
+	/* filter HTML in Body */
+	if((CFlags & MSG_CHK_ALLOW_HTML) == 0) {
+		if(*body != NULL) {
+			char *st = FilterHTMLTags(*body, MAX_PARAMETERS_STRING - 1);
+			free(*body);
+			*body = st;
+		}
+	}
+
+#if SPELLING_CHECK == 1
+	// spelling check
+	// if disallowed word was found in header we should boiling out
+	if(FilterBadWords(mes->MessageHeader)) return MSG_CHK_ERROR_BADSPELLING;
+	if(FilterBadWords(mes->AuthorName)) return MSG_CHK_ERROR_BADSPELLING;
+	// we should only replace with '#' all bad words in body
+	FilterBadWords(*body);
+#endif
+
+	/* parse WWWConf Tags and smiles */
+
+	/* set flags for body */
+	flg = MESSAGE_ENABLED_SMILES | MESSAGE_ENABLED_TAGS;
+
+	if(CFlags & MSG_CHK_DISABLE_SMILE_CODES) {
+		flg = flg & (~MESSAGE_ENABLED_SMILES);
+	}
+	if(CFlags & MSG_CHK_DISABLE_WWWCONF_TAGS) {
+		flg = flg & (~MESSAGE_ENABLED_TAGS);
+	}
+
+	/* parse body */
+	if(FilterBoardTags(*body, &st, mes->Security, MAX_PARAMETERS_STRING, flg | BOARDTAGS_TAG_PREPARSE, RetFlags) == 0) {
+		/* if to long - ignore tags */
+		*RetFlags = 0;
+	}
+	else {
+		free(*body);
+		if(strcmp(st, " ") == 0) *st = 0;
+		*body = st;
+	}
+
+	return MSG_CHK_ERROR_PASSED;
+}
blob - /dev/null
blob + 23db09b813995a9e90cfb29fa65d01d9efd34b57 (mode 644)
--- /dev/null
+++ src/speller.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+                          speller.h  -  spelling, ban, html cheker header
+                             -------------------
+    begin                : Mon Mar 19 2001
+    copyright            : (C) 2001 by Alexander Bilichenko
+    email                : pricer@mail.ru
+ ***************************************************************************/
+
+#ifndef SPELLER_H_INCLUDED
+#define SPELLER_H_INCLUDED
+
+#include "basetypes.h"
+#include "profiles.h"
+#include "dbase.h"
+
+/* error codes for CheckSpellingBan() */
+#define MSG_CHK_ERROR_PASSED			1
+#define MSG_CHK_ERROR_NONAME			2
+//#define MSG_CHK_ERROR_NOEMAIL			3
+#define MSG_CHK_ERROR_NOMSGHEADER		4
+#define MSG_CHK_ERROR_NOMSGBODY			5
+#define MSG_CHK_ERROR_BADSPELLING		6
+#define MSG_CHK_ERROR_BANNED			7
+#define MSG_CHK_ERROR_CLOSED			8
+#define MSG_CHK_ERROR_INVALID_REPLY		9
+#define MSG_CHK_ERROR_INVALID_PASSW		10
+#define MSG_CHK_ERROR_ROBOT_MESSAGE		11
+
+#define PROFILE_CHK_ERROR_ALLOK					1
+#define PROFILE_CHK_ERROR_ALREADY_EXIST			2
+#define PROFILE_CHK_ERROR_NOT_EXIST				3
+#define PROFILE_CHK_ERROR_INVALID_LOGIN_SPELL	4
+#define PROFILE_CHK_ERROR_INVALID_PASSWORD		5
+#define PROFILE_CHK_ERROR_INVALID_PASSWORD_REP	6
+#define PROFILE_CHK_ERROR_SHORT_PASSWORD		7
+#define PROFILE_CHK_ERROR_INVALID_EMAIL			8
+#define PROFILE_CHK_ERROR_CANNOT_DELETE_USR		9
+#define PROFILE_CHK_ERROR_UNKNOWN_ERROR			10
+
+#define SPELLER_FILTER_HTML						0x0002
+#define SPELLER_PARSE_TAGS						0x0001
+
+/* bit mask of CFlags format in CheckSpellingBan() */
+#define MSG_CHK_DISABLE_WWWCONF_TAGS			0x0001
+#define MSG_CHK_DISABLE_SMILE_CODES				0x0002
+#define MSG_CHK_ENABLE_EMAIL_ACKNL				0x0004
+#define MSG_CHK_ALLOW_HTML						0x0008
+#define MSG_CHK_DISABLE_SIGNATURE				0x0010
+
+#define SPELLER_INTERNAL_BUFFER_SIZE			10000
+
+/* code string to http format, if allocmem = 1 - function will allocate memory for you,
+ * otherwise internal buffer will be used (10K buffer) */
+char* CodeHttpString(char *s, int allocmem = 1);
+
+/* check email (with current #define settings) */
+int IsMailCorrect(char *s);
+
+/* Preprare message under WIN32 for preview - actually filter char #10 */
+void FilterMessageForPreview(char *s, char **dd);
+
+/* filter html tags, if allocmem = 1 - function will allocate memory for you,
+ * otherwise internal buffer will be used (10K buffer) */
+char* FilterHTMLTags(char *s, WORD ml, int allocmem = 1);
+
+char* FilterWhitespaces(char *s);
+
+/* prepare every text in this board to be printed to browser */
+int PrepareTextForPrint(char *msg, char **res, BYTE security, int flags, int spfl = SPELLER_FILTER_HTML | SPELLER_PARSE_TAGS);
+
+/* check message for correct and check HTML Tags, bad words list, and banned user */
+int CheckSpellingBan(struct SMessage *mes, char **body, char **Reason, 
+					 DWORD CFlags, DWORD *RetFlags, bool fRegged = true);
+
+#endif
blob - /dev/null
blob + a83cc65c3ce8258e9df61d6f9e5c6e0fa3c73e23 (mode 644)
--- /dev/null
+++ src/statfs.cpp
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include "statfs.h" 
+
+typedef signed long long i64;
+
+bool isEnoughSpace(void)
+{
+/*	const i64 minsize = 10 * 1000 * 1000; //10Mb
+	struct statfs fsi;
+	if(statfs(".", &fsi))
+		return false;*/
+//	printf(
+//		"fs stats: fsi.f_bsize: %u; fsi.f_bavail: %u\n", 
+//		fsi.f_bsize, 
+//		fsi.f_bavail);
+	//return (i64)fsi.f_bsize * (i64)fsi.f_bavail > minsize;
+	return 1;
+}
blob - /dev/null
blob + 3abf1b4566c8181c76db101e13eb89d3846f610d (mode 644)
--- /dev/null
+++ src/statfs.h
@@ -0,0 +1 @@
+bool isEnoughSpace(void);