commit 7dc1039c56f1f1a35707aea31b6bf10028f6c20e
from: Sergey Bronnikov Quotation:
", WC_TAG_TYPE_ONLYOPEN, "", WC_TAG_TYPE_DISABLED, 2},
+ /* quotation */
+ {"Q", "
", WC_TAG_TYPE_1, "", WC_TAG_TYPE_1, 10}, + {"STRIKE", "
"); + /* 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." "" DESIGN_FAVORITES_DEL_THREAD " ", + 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("
"); + 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("%s", 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(" " + DESIGN_FAVORITES_ADD_THREAD "", favtemp); + break; + case PROFILE_RETURN_ALREADY_EXIST: + printf(" " + DESIGN_FAVORITES_DEL_THREAD "", 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
\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("An error occured
Try to refresh this page, and if" + " this occure again please contact server " + " administrator for support", ADMIN_MAIL); +#if ERROR_ON_SCREEN == 0 +#if ENABLE_LOG + printf("
This error have been logged to the"
+ " server log");
+#endif
+#else
+ printf(" Technical details ");
+}
+
+static void PrintLoginForm()
+{
+ printf("
" \
+ "" LOG_UNHANDLED_HTML, file, line, getenv(REMOTE_ADDR),
+ (s && (*s != 0)) ? s : LOG_ERRORTYPEUNKN, getenv(QUERY_STRING));
+#endif
+ printf("");
+ 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
",
+ 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("%s", 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("%s",
+ MY_CGI_URL, ret, MESSAGEMAIN_post_replymessage);
+ else printf("%s",
+ 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("%s",
+ MY_CGI_URL, MESSAGEHEAD_return_to_main_page);
+ else printf("%s",
+ MY_CGI_URL, ind, MESSAGEHEAD_return_to_main_page);
+ g = 1;
+ }
+
+ if(c & HEADERSTRING_POST_NEW_MESSAGE) {
+ if(g) printf(DESIGN_BUTTONS_DIVIDER);
+ printf("%s", MY_CGI_URL, MESSAGEHEAD_post_new_message);
+ g = 1;
+ }
+
+ if((c & HEADERSTRING_DISABLE_SEARCH) == 0) {
+ if(g) printf(DESIGN_BUTTONS_DIVIDER);
+ printf("%s", MY_CGI_URL, MESSAGEHEAD_search);
+ g = 1;
+ }
+
+ if(c & HEADERSTRING_CONFIGURE) {
+ if(g) printf(DESIGN_BUTTONS_DIVIDER);
+ printf("%s", MY_CGI_URL, MESSAGEHEAD_configure);
+ g = 1;
+ }
+
+ if(c & HEADERSTRING_ENABLE_RESETNEW) {
+ if(g) printf(DESIGN_BUTTONS_DIVIDER);
+ printf("%s", 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("%s", MY_CGI_URL, MESSAGEHEAD_registerprf);
+ else
+ printf("%s", MY_CGI_URL, MESSAGEHEAD_register);
+ g = 1;
+ }
+
+ if(c & HEADERSTRING_REG_USER_LIST) {
+ if(g) printf(DESIGN_BUTTONS_DIVIDER);
+ printf("%s", 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("%s", MY_CGI_URL, MESSAGEHEAD_banlist);
+ }
+
+ if((ULogin.LU.ID[0] == 0) && ((c & HEADERSTRING_DISABLE_LOGIN) == 0)) {
+ if(g) printf(DESIGN_BUTTONS_DIVIDER);
+ printf("%s", MY_CGI_URL, MESSAGEHEAD_login);
+ g = 1;
+ }
+
+ if((c & HEADERSTRING_DISABLE_FAQHELP) == 0) {
+ if(g) printf(DESIGN_BUTTONS_DIVIDER);
+ printf("" MESSAGEHEAD_help_showhelp "");
+ g = 1;
+ }
+
+#if USER_FAVOURITES_SUPPORT
+ if(ULogin.LU.ID[0] != 0 && (c & HEADERSTRING_DISABLE_FAVOURITES) == 0) {
+ if(g) printf(DESIGN_BUTTONS_DIVIDER);
+ printf("%s",
+ 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("");
+ printf(DESIGN_COMMAND_TABLE_BEGIN);
+ printf("");
+ //gray space after top links
+ printf(" ");
+ printf("");
+ }
+
+}
+
+/* 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("