bool iscan1(int si) // Initializes use of a sub value (subboards[], not usub[]). If quick, then // don't worry about anything detailed, just grab qscan info. { postrec p; // make sure we have cache space if (!cache) { cache = static_cast<postrec *>(malloc(MAX_TO_CACHE * sizeof(postrec))); if (!cache) { return false; } } // forget it if an invalid sub # if (si < 0 || si >= initinfo.num_subs) { return false; } // see if a sub has changed if (subchg) { SetCurrentReadMessageArea(-1); } // if already have this one set, nothing more to do if (si == GetCurrentReadMessageArea()) { return true; } // sub cache no longer valid believe_cache = false; // set sub filename snprintf(subdat_fn, sizeof(subdat_fn), "%s%s.sub", syscfg.datadir, subboards[si].filename); // open file, and create it if necessary if (!WFile::Exists(subdat_fn)) { if (!open_sub(true)) { return false; } p.owneruser = 0; fileSub.Write(&p, sizeof(postrec)); } else if (!open_sub(false)) { return false; } // set sub SetCurrentReadMessageArea(si); subchg = 0; last_msgnum = 0; // read in first rec, specifying # posts fileSub.Seek(0L, WFile::seekBegin); fileSub.Read(&p, sizeof(postrec)); SetNumMessagesInCurrentMessageArea(p.owneruser); // close file close_sub(); // iscanned correctly return true; }
void add_post(postrec *pp) { postrec p; int close_file=0; /* open the sub, if necessary */ if (sub_f <= 0) { open_sub(1); close_file=1; } if (sub_f>=0) { /* get updated info */ read_status(); sh_lseek(sub_f, 0L, SEEK_SET); sh_read(sub_f, &p, sizeof(postrec)); /* one more post */ p.owneruser++; nummsgs=p.owneruser; sh_lseek(sub_f, 0L, SEEK_SET); sh_write(sub_f, &p, sizeof(postrec)); /* add the new post */ sh_lseek(sub_f, ((long)nummsgs)*sizeof(postrec), SEEK_SET); sh_write(sub_f, pp, sizeof(postrec)); /* we've modified the sub */ believe_cache=0; subchg=0; sub_dates[curlsub]=pp->qscan; } if (close_file) close_sub(); }
void post(void) { messagerec m; postrec p; char s[121]; int i,dm,a,flag; time_t time1, time2; flag=0; m.storage_type=subboards[curlsub].storage_type; a=0; time1=time(NULL); // write_inst(INST_LOC_POST,curlsub,INST_FLAGS_NONE); // inmsg(&m,p.title,&a,1,(subboards[curlsub].filename),ALLOW_FULLSCREEN, // subboards[curlsub].name, (subboards[curlsub].anony&anony_no_tag)?1:0); savefile(buffer,length,&m,(subboards[curlsub].filename)); if (m.stored_as!=0xffffffff) { p.anony=a; p.msg=m; p.ownersys=0; p.owneruser=usernum; lock_status(); p.qscan=status.qscanptr++; save_status(); time((long *)(&p.daten)); p.status=0; open_sub(1); if ((xsubs[curlsub].num_nets) && (subboards[curlsub].anony & anony_val_net) && (!lcs() || irt[0])) { p.status |= status_pending_net; dm=1; for (i=nummsgs; (i>=1) && (i>(nummsgs-28)); i--) { if (get_post(i)->status & status_pending_net) { dm=0; break; } } if (dm) { sprintf(s,get_stringx(1,37),subboards[curlsub].name); ssm(1,0,s); } } if (nummsgs>=subboards[curlsub].maxmsgs) { i=1; dm=0; while ((dm==0) && (i<=nummsgs)) { if ((get_post(i)->status & status_no_delete)==0) dm=i; ++i; } if (dm==0) dm=1; delete(dm); } add_post(&p); lock_status(); ++status.msgposttoday; ++status.localposts; save_status(); close_sub(); if (xsubs[curlsub].num_nets) { if (!(p.status & status_pending_net)) send_net_post(&p, subboards[curlsub].filename, curlsub); } } }
void valscan() { // Must be local cosysop or better if (!lcs()) { return; } int ac = 0; int os = GetSession()->GetCurrentMessageArea(); if (uconfsub[1].confnum != -1 && okconf(GetSession()->GetCurrentUser())) { ac = 1; tmp_disable_conf(true); } bool done = false; for (int sn = 0; sn < GetSession()->num_subs && !hangup && !done; sn++) { if (!iscan(sn)) { continue; } if (GetSession()->GetCurrentReadMessageArea() < 0) { return; } uint32_t sq = qsc_p[sn]; // Must be sub with validation "on" if (!(xsubs[GetSession()->GetCurrentReadMessageArea()].num_nets) || !(subboards[GetSession()->GetCurrentReadMessageArea()].anony & anony_val_net)) { continue; } GetSession()->bout.NewLine(); GetSession()->bout.Color(2); GetSession()->bout.ClearEOL(); GetSession()->bout << "{{ ValScanning " << subboards[GetSession()->GetCurrentReadMessageArea()].name << " }}\r\n"; lines_listed = 0; GetSession()->bout.ClearEOL(); if (okansi() && !newline) { GetSession()->bout << "\r\x1b[2A"; } for (int i = 1; i <= GetSession()->GetNumMessagesInCurrentMessageArea() && !hangup && !done; i++) { // was i = 0 if (get_post(i)->status & status_pending_net) { CheckForHangup(); GetSession()->localIO()->tleft(true); if (i > 0 && i <= GetSession()->GetNumMessagesInCurrentMessageArea()) { bool next; int val; read_message(i, &next, &val); GetSession()->bout << "|#4[|#4Subboard: " << subboards[GetSession()->GetCurrentReadMessageArea()].name << "|#1]\r\n"; GetSession()->bout << "|#1D|#9)elete, |#1R|#9)eread |#1V|#9)alidate, |#1M|#9)ark Validated, |#1Q|#9)uit: |#2"; char ch = onek("QDVMR"); switch (ch) { case 'Q': done = true; break; case 'R': i--; continue; case 'V': { open_sub(true); resynch(&i, nullptr); postrec *p1 = get_post(i); p1->status &= ~status_pending_net; write_post(i, p1); close_sub(); send_net_post(p1, subboards[GetSession()->GetCurrentReadMessageArea()].filename, GetSession()->GetCurrentReadMessageArea()); GetSession()->bout.NewLine(); GetSession()->bout << "|#7Message sent.\r\n\n"; } break; case 'M': if (lcs() && i > 0 && i <= GetSession()->GetNumMessagesInCurrentMessageArea() && subboards[GetSession()->GetCurrentReadMessageArea()].anony & anony_val_net && xsubs[GetSession()->GetCurrentReadMessageArea()].num_nets) { open_sub(true); resynch(&i, nullptr); postrec *p1 = get_post(i); p1->status &= ~status_pending_net; write_post(i, p1); close_sub(); GetSession()->bout.NewLine(); GetSession()->bout << "|#9Not set for net pending now.\r\n\n"; } break; case 'D': if (lcs()) { if (i > 0) { open_sub(true); resynch(&i, nullptr); postrec p2 = *get_post(i); delete_message(i); close_sub(); if (p2.ownersys == 0) { WUser tu; GetApplication()->GetUserManager()->ReadUser(&tu, p2.owneruser); if (!tu.IsUserDeleted()) { if (static_cast<unsigned long>(date_to_daten(tu.GetFirstOn())) < p2.daten) { GetSession()->bout.NewLine(); GetSession()->bout << "|#2Remove how many posts credit? "; char szNumCredits[ 11 ]; input(szNumCredits, 3, true); int nNumPostCredits = 1; if (szNumCredits[0]) { nNumPostCredits = atoi(szNumCredits); } nNumPostCredits = std::min<int>(tu.GetNumMessagesPosted(), nNumPostCredits); if (nNumPostCredits) { tu.SetNumMessagesPosted(tu.GetNumMessagesPosted() - static_cast<unsigned short>(nNumPostCredits)); } GetSession()->bout.NewLine(); GetSession()->bout << "|#3Post credit removed = " << nNumPostCredits << wwiv::endl; tu.SetNumDeletedPosts(tu.GetNumDeletedPosts() + 1); GetApplication()->GetUserManager()->WriteUser(&tu, p2.owneruser); GetApplication()->UpdateTopScreen(); } } } resynch(&i, &p2); } } break; } } } } qsc_p[sn] = sq; } if (ac) { tmp_disable_conf(false); } GetSession()->SetCurrentMessageArea(os); GetSession()->bout.NewLine(2); }
postrec *get_post(unsigned short mn) /* * Returns info for a post. Maintains a cache. Does not correct anything * if the sub has changed. */ { postrec p; int close_file; if (mn==0) return(NULL); if (subchg==1) { /* sub has changed (detected in read_status); invalidate cache */ believe_cache=0; /* kludge: subch==2 leaves subch indicating change, but the '2' value */ /* indicates, to this routine, that it has been handled at this level */ subchg=2; } /* see if we need new cache info */ if ((!believe_cache) || (mn<cache_start) || (mn>=(cache_start+MAX_TO_CACHE))) { if (sub_f < 0) { /* open the sub data file, if necessary */ if (open_sub(0)<0) return(NULL); close_file = 1; } else { close_file = 0; } /* re-read # msgs, if needed */ if (subchg==2) { sh_lseek(sub_f, 0L, SEEK_SET); sh_read(sub_f, &p, sizeof(postrec)); nummsgs=p.owneruser; /* another kludge: subch==3 indicates we have re-read # msgs also */ /* only used so we don't do this every time through */ subchg=3; /* adjust msgnum, if it is no longer valid */ if (mn>nummsgs) mn=nummsgs; } /* select new starting point of cache */ if (mn >= last_msgnum) { /* going forward */ if (nummsgs<=MAX_TO_CACHE) cache_start=1; else if (mn>(nummsgs-MAX_TO_CACHE)) cache_start=nummsgs-MAX_TO_CACHE+1; else cache_start = mn; } else { /* going backward */ if (mn>MAX_TO_CACHE) cache_start = mn-MAX_TO_CACHE+1; else cache_start = 1; } if (cache_start<1) cache_start=1; /* read in some sub info */ sh_lseek(sub_f, ((long) cache_start)*sizeof(postrec), SEEK_SET); sh_read(sub_f, cache, MAX_TO_CACHE*sizeof(postrec)); /* now, close the file, if necessary */ if (close_file) { close_sub(); } /* cache is now valid */ believe_cache = 1; } /* error if msg # invalid */ if ((mn<1) || (mn>nummsgs)) return(NULL); last_msgnum=mn; return(cache+(mn-cache_start)); }
int iscan1(int si, int quick) /* * Initializes use of a sub value (subboards[], not usub[]). If quick, then * don't worry about anything detailed, just grab qscan info. */ { postrec p; /* make sure we have cache space */ if (!cache) { cache=malloca(MAX_TO_CACHE*sizeof(postrec)); if (!cache) return(0); } /* forget it if an invalid sub # */ if ((si<0) || (si>=num_subs)) return(0); /* skip this stuff if being called from the WFC cache code */ if (!quick) { /* go to correct net # */ if (xsubs[si].num_nets) set_net_num(xsubs[si].nets[0].net_num); else set_net_num(0); /* see if a sub has changed */ read_status(); /* if already have this one set, nothing more to do */ if (si==currsub) return(1); } currsub=si; /* sub cache no longer valid */ believe_cache=0; /* set sub filename */ sprintf(subdat_fn,"%s%s.SUB",syscfg.datadir,subboards[si].filename); /* open file, and create it if necessary */ if (open_sub(0)<0) { if (open_sub(1)<0) return(0); p.owneruser=0; sh_write(sub_f,(void *) &p,sizeof(postrec)); } /* set sub */ curlsub=si; subchg=0; last_msgnum=0; /* read in first rec, specifying # posts */ sh_lseek(sub_f,0L,SEEK_SET); sh_read(sub_f,&p, sizeof(postrec)); nummsgs=p.owneruser; /* read in sub date, if don't already know it */ if (sub_dates[si]==0) { if (nummsgs) { sh_lseek(sub_f, ((long) nummsgs)*sizeof(postrec), SEEK_SET); sh_read(sub_f, &p, sizeof(postrec)); sub_dates[si]=p.qscan; } else { sub_dates[si]=1; } } /* close file */ close_sub(); /* iscanned correctly */ return(1); }
void deletemsg(int mn) { postrec *p1, p; int close_file=0; unsigned int nb; char *buf; // char scratch[181]; long len, l, cp; /* open file, if needed */ if (sub_f <= 0) { open_sub(1); close_file=1; } /* see if anything changed */ read_status(); if (sub_f >= 0) { if ((mn>0) && (mn<=nummsgs)) { buf=(char *)malloca(BUFSIZE); if (buf) { p1=get_post(mn); remove_link(&(p1->msg),(subboards[curlsub].filename)); cp=((long)mn+1)*sizeof(postrec); len=((long)(nummsgs+1))*sizeof(postrec); do { l=len-cp; if (l<BUFSIZE) nb=(int)l; else nb=BUFSIZE; if (nb) { sh_lseek(sub_f, cp, SEEK_SET); sh_read(sub_f, buf, nb); sh_lseek(sub_f, cp-sizeof(postrec), SEEK_SET); sh_write(sub_f, buf, nb); cp += nb; } } while (nb==BUFSIZE); /* update # msgs */ sh_lseek(sub_f, 0L, SEEK_SET); sh_read(sub_f, &p, sizeof(postrec)); p.owneruser--; nummsgs=p.owneruser; sh_lseek(sub_f, 0L, SEEK_SET); sh_write(sub_f, &p, sizeof(postrec)); /* cache is now invalid */ believe_cache = 0; bbsfree(buf); } } } /* close file, if needed */ if (close_file) close_sub(); }
/*! Create Sub-File/Directory to \c this with local name \p pathL. * \return 0 on success, -1 on error and see \c errno. */ int create_sub(const csc& pathL, mode_t mode = PDIR_SUB_MODE) { return open_sub(pathL, O_CREAT|O_WRONLY|O_TRUNC, mode); }
postrec *get_post(int mn) // Returns info for a post. Maintains a cache. Does not correct anything // if the sub has changed. { postrec p; bool bCloseSubFile = false; if (mn == 0) { return nullptr; } if (subchg == 1) { // sub has changed (detected in GetApplication()->GetStatusManager()->Read); invalidate cache believe_cache = false; // kludge: subch==2 leaves subch indicating change, but the '2' value // indicates, to this routine, that it has been handled at this level subchg = 2; } // see if we need new cache info if (!believe_cache || mn < cache_start || mn >= (cache_start + MAX_TO_CACHE)) { if (!fileSub.IsOpen()) { // open the sub data file, if necessary if (!open_sub(false)) { return nullptr; } bCloseSubFile = true; } // re-read # msgs, if needed if (subchg == 2) { fileSub.Seek(0L, WFile::seekBegin); fileSub.Read(&p, sizeof(postrec)); SetNumMessagesInCurrentMessageArea(p.owneruser); // another kludge: subch==3 indicates we have re-read # msgs also // only used so we don't do this every time through subchg = 3; // adjust msgnum, if it is no longer valid if (mn > GetNumMessagesInCurrentMessageArea()) { mn = GetNumMessagesInCurrentMessageArea(); } } // select new starting point of cache if (mn >= last_msgnum) { // going forward if (GetNumMessagesInCurrentMessageArea() <= MAX_TO_CACHE) { cache_start = 1; } else if (mn > (GetNumMessagesInCurrentMessageArea() - MAX_TO_CACHE)) { cache_start = GetNumMessagesInCurrentMessageArea() - MAX_TO_CACHE + 1; } else { cache_start = mn; } } else { // going backward if (mn > MAX_TO_CACHE) { cache_start = mn - MAX_TO_CACHE + 1; } else { cache_start = 1; } } if (cache_start < 1) { cache_start = 1; } // read in some sub info fileSub.Seek(cache_start * sizeof(postrec), WFile::seekBegin); fileSub.Read(cache, MAX_TO_CACHE * sizeof(postrec)); // now, close the file, if necessary if (bCloseSubFile) { close_sub(); } // cache is now valid believe_cache = true; } // error if msg # invalid if (mn < 1 || mn > GetNumMessagesInCurrentMessageArea()) { return nullptr; } last_msgnum = mn; return (cache + (mn - cache_start)); }