void DeleteConnection(Connection *conn) { MemPool *mpool = conn->co_MemPool; if (conn->co_Desc->d_Type == THREAD_SPOOL) { conn->co_LastServerLog = 1; LogServerInfo(conn, TFd); } else if (conn->co_Desc->d_Type == THREAD_NNTP) { char statbuf[1024]; char vsbuf[11]; char hsbuf[31]; snprintf(vsbuf, sizeof(vsbuf), "%s", conn->co_Auth.dr_VServerDef->vs_Name); snprintf(hsbuf, sizeof(hsbuf), "%s%s%s%s%s", *conn->co_Auth.dr_AuthUser ? conn->co_Auth.dr_AuthUser : "", *conn->co_Auth.dr_AuthUser ? "/" : "", *conn->co_Auth.dr_IdentUser ? conn->co_Auth.dr_IdentUser : "", *conn->co_Auth.dr_IdentUser ? "@" : "", conn->co_Auth.dr_Host); RTStatusBase(conn->co_Desc->d_Slot, "CLSD %-10s %-30s", vsbuf, hsbuf); GroupStats(conn); snprintf(statbuf, sizeof(statbuf), "exit articles %lu groups %lu posts %lu bytes %.0f", conn->co_ClientTotalArticleCount, conn->co_ClientGroupCount, conn->co_ClientPostCount, conn->co_ClientTotalByteCount); LogCmd(conn, '$', statbuf); StatusUpdate(conn, "(closed)"); freeReaderSlot(conn->co_Desc->d_Slot); --NumReaders; /* * Inform the main server that we are done with the descriptor * by writing the DnsRes structure back to it, so the main server * can track who from where is connecting to what and when that * connection terminates. */ conn->co_Auth.dr_ByteCount = conn->co_TMBuf.mh_TotalBytes; SendMsg(TFd, conn->co_Desc->d_Fd, &conn->co_Auth); } FreeControl(conn); freePool(&conn->co_BufPool); freePool(&mpool); /* includes Connection structure itself */ }
BOOL ParseDirLine(Connection *Connect,BOOL AllFiles,FTPFileInfo* p) { PROC(("ParseDirLine", "%p,%d", Connect, AllFiles)) String Line, Line1; FTPDirList dl; FTPServerInfo si; while(true) { Connect->GetOutput(Line); if(!Line.Length()) break; if(strstr(Line.c_str(),": Permission denied")) { WINPORT(SetLastError)(ERROR_ACCESS_DENIED); return FALSE; } if(Line.Length() < 20) continue; //Check contains skipped text static LPCSTR FTPMsg[] = { "data connection", "transfer complete", "bytes received", "DEVICE:[", "Total of " }; BOOL Found = FALSE; for(size_t n = 0; n < ARRAYSIZE(FTPMsg); n++) if(strstr(Line.c_str(),FTPMsg[n])) { Found = TRUE; break; } if(Found) continue; //Check special skip strings if(StrCmp(Line.c_str(), "Directory ", 10) == 0 && strchr(Line.c_str()+10,'[') != NULL) continue; //Set start detect info memset(p, 0, sizeof(*p)); si.ServerType = Connect->Host.ServerType; StrCpy(si.ServerInfo, Connect->SystemInfo, ARRAYSIZE(si.ServerInfo)); //Use temp buffer Line1 = Line; //Detect WORD idx; FTPType* tp = dl.GetType(Connect->Host.ServerType); if(Connect->Host.ServerType == FTP_TYPE_DETECT || Connect->Host.ServerType == FTP_TYPE_INVALID || tp == NULL) { idx = dl.DetectStringType(&si, Line.c_str(), Line.Length()); if(idx == FTP_TYPE_INVALID || (tp=dl.GetType(idx)) == NULL) { LogCmd(Message("ParserDETECT: %s->%s [%s]", Parser2Str(Connect->Host.ServerType,&dl), Parser2Str(idx,&dl), Line1.c_str()), ldInt); if(Connect->Host.ServerType != FTP_TYPE_DETECT && Connect->Host.ServerType != FTP_TYPE_INVALID) { LogCmd(Message("ParserIGNORE: [%s]", Line1.c_str()), ldInt); Connect->AddCmdLine(Message("ParserIGNORE: [%s]", Line1.c_str())); continue; } BadFormat(Connect,Line1.c_str(),FALSE); break; } else { Log(("ParserDETECTED: %s->%s [%s]",Parser2Str(Connect->Host.ServerType,&dl),Parser2Str(idx,&dl),Line1.c_str())); Connect->Host.ServerType = idx; } } else idx = Connect->Host.ServerType; //Use temp buffer Line = Line1; Log(("toParse: %d,[%s], %d",Line.Length(),Line.c_str())); //Parse if(!tp->Parser(&si,p,Line.c_str(),Line.Length())) { LogCmd(Message("ParserFAIL: %s->%s [%s]", Parser2Str(Connect->Host.ServerType,&dl), Parser2Str(idx,&dl), Line1.c_str()), ldInt); Connect->AddCmdLine(Message("ParserFAIL: (%s) [%s]", Parser2Str(idx,&dl), Line1.c_str())); continue; } //Skip entryes char *CurName = FTP_FILENAME(p); if(p->FileType == NET_SKIP || !CurName[0] || StrCmp(CurName,".") == 0 || (!AllFiles && StrCmp(CurName,"..") == 0)) continue; //Correct attrs if(p->FileType == NET_DIRECTORY || p->FileType == NET_SYM_LINK_TO_DIR) SET_FLAG(p->FindData.dwFileAttributes,FILE_ATTRIBUTE_DIRECTORY); if(p->FileType == NET_SYM_LINK_TO_DIR || p->FileType == NET_SYM_LINK) SET_FLAG(p->FindData.dwFileAttributes,FILE_ATTRIBUTE_REPARSE_POINT); //Convert name text // Connect->ToOEM(CurName); //OK return TRUE; } WINPORT(SetLastError)(ERROR_NO_MORE_FILES); return FALSE; }
void NNFeedOverview(Connection *conn) { int artLen; int l = 0; char *art = MBNormalize(&conn->co_ArtBuf, &artLen); char *line; int appr = 0; char ch; int err = 0; char *newsgroups = NULL; char *msgid = NULL; char *subject = NULL; char *date = NULL; char *xref = NULL; char *control = NULL; char *supers = NULL; /* Supersedes */ /* * Scan headers, look for Newsgroups: line, Subject:, Date:, From:, and * Message-Id:. If any are missing, the article is bad. If there is an * Xref: line, save that too and use it to calculate line numbers if * Xref operation is enabled. * * We allow an LF-only line to terminate the headers as well as CR+LF, * because some news systems are totally broken. */ for (line = art; line < art + artLen; line += l + 1) { for (l = line - art; l < artLen; ++l) { if (art[l] == '\n') { if (l + 1 >= artLen || /* past end of article */ l == line - art || /* blank line */ (art[l+1] != ' ' && art[l+1] != '\t') /* !header ext */ ) { break; } } } l -= line - art; ch = tolower(*line); if (l == 0 || (l == 1 && line[0] == '\r')) { /* out of headers */ break; } else if (ch == 'n' && strncasecmp(line, "Newsgroups:", 11) == 0) { newsgroups = zallocStrTrim2(&conn->co_MemPool, ',', line + 11, l - 11); } else if (ch == 'm' && strncasecmp(line, "Message-ID:", 11) == 0) { msgid = zallocStrTrim2(&conn->co_MemPool, 0, line + 11, l - 11); } else if (ch == 's' && strncasecmp(line, "Subject:", 8) == 0) { subject = zallocStrTrim2(&conn->co_MemPool, 0, line + 8, l - 8); } else if (ch == 'd' && strncasecmp(line, "Date:", 5) == 0) { date = zallocStrTrim2(&conn->co_MemPool, 0, line + 5, l - 5); } else if (ch == 'x' && strncasecmp(line, "Xref:", 5) == 0) { xref = zallocStrTrim2(&conn->co_MemPool, ',', line + 5, l - 5); } else if (ch == 'c' && strncasecmp(line, "Control:", 8) == 0) { control = zallocStrTrim2(&conn->co_MemPool, 0, line + 8, l - 8); } else if (ch == 's' && strncasecmp(line, "Supersedes:", 11) == 0) { supers = zallocStrTrim2(&conn->co_MemPool, 0, line + 11, l - 11); } else if (ch == 'a' && strncasecmp(line, "Approved:", 9) == 0) { appr = 1; } } if (conn->co_Flags & COF_POSTTOOBIG) { conn->co_Auth.dr_PostFailCount++; if (conn->co_Flags & COF_IHAVE) { MBLogPrintf(conn, &conn->co_TMBuf, "437 Rejected, too big\r\n"); } else { MBLogPrintf(conn, &conn->co_TMBuf, "439 %s too big\r\n", conn->co_IHaveMsgId); } conn->co_Flags &= ~COF_POSTTOOBIG; } else if (newsgroups == NULL || msgid == NULL || subject == NULL || date == NULL || strcmp(msgid, "<>") == 0 ) { /* * failure */ conn->co_Auth.dr_PostFailCount++; if (conn->co_Flags & COF_IHAVE) { MBLogPrintf(conn, &conn->co_TMBuf, "437 Rejected, headers missing\r\n"); } else { MBLogPrintf(conn, &conn->co_TMBuf, "439 %s\r\n", conn->co_IHaveMsgId); } } else if (conn->co_ByteCounter == 0.0 && conn->co_BytesHeader == 0) { conn->co_Auth.dr_PostFailCount++; if (conn->co_Flags & COF_IHAVE) { MBLogPrintf(conn, &conn->co_TMBuf, "437 Rejected, Bytes header missing for header-only feed\r\n"); } else { MBLogPrintf(conn, &conn->co_TMBuf, "439 %s headerOnlyFeed requires Bytes header\r\n", conn->co_IHaveMsgId); } } else if (FindCancelCache(msgid) == 0) { char logbuf[1024]; conn->co_Auth.dr_PostFailCount++; snprintf(logbuf, sizeof(logbuf), "%s cancel cache", msgid); LogCmd(conn, '-', logbuf); if (DRIncomingLogPat != NULL) LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf); if (conn->co_Flags & COF_IHAVE) { MBLogPrintf(conn, &conn->co_TMBuf, "437 Article Already Cancelled\r\n"); } else { MBLogPrintf(conn, &conn->co_TMBuf, "439 %s Article Already Cancelled\r\n", conn->co_IHaveMsgId); } } else { /* * write out overview information */ char *group; char *ngroup = NULL; ArtNumAss *ANABase = NULL; /* * if it is a control message, we don't really care what the newsgroups * line says. instead, we cobble up "control.<type>" or just "control" */ if (conn->co_Flags & COF_WASCONTROL) { char cmsgtype[64]; char *cptr; cptr = control; while (*cptr == ' ' || *cptr == '\t') { cptr++; } snprintf(cmsgtype, sizeof(cmsgtype), "control%s%s", *cptr ? "." : "", cptr); if (((cptr = strchr(cmsgtype, ' '))) || ((cptr = strchr(cmsgtype, '\t')))) { *cptr = '\0'; } zfreeStr(&conn->co_MemPool, &newsgroups); newsgroups = zallocStr(&conn->co_MemPool, cmsgtype); } if (DebugOpt) printf("Feed overview %s %s\n", msgid, newsgroups); /* * pass 1 - assign article numbers */ for (group = newsgroups; *group; group = ngroup) { char c; char whspc = 0; char *whspptr; /* Strip leading spaces */ while (*group == ' ' || *group == '\t') { group++; } if (! *group) { break; } for (ngroup = group; *ngroup && *ngroup != ','; ++ngroup) ; c = *ngroup; *ngroup = 0; /* * Skip groups with names that are too long */ if (ngroup - group > MAXGNAME) continue; /* Strip trailing space or tab from group name */ whspptr = strpbrk(group, " \t"); if (whspptr) { whspc = *whspptr; *whspptr = 0; } AssignArticleNo(conn, &ANABase, group, xref, appr, art, artLen, msgid); /* Repair string back to its former state */ if (whspptr) { *whspptr = whspc; } *ngroup = c; if (*ngroup == ',') ++ngroup; } /* * Supersedes is allowed on non-control messages. We execute the * cancel AND post the article. Note: we do not allow supersedes * on Control: messages. (XXX is this still true with the new logic? JG) */ if (supers) { if (DebugOpt) printf("has Supersedes: %s %s\n", msgid, newsgroups); ExecuteSupersedes(conn, supers, art, artLen); } err = 0; for (group = newsgroups; *group; group = ngroup) { char c; char whspc = 0; char *whspptr; for (ngroup = group; *ngroup && *ngroup != ','; ++ngroup) ; c = *ngroup; *ngroup = 0; /* * Skip groups with names that are too long */ if (ngroup - group > MAXGNAME) continue; /* Strip trailing space or tab from group name */ whspptr = strpbrk(group, " \t"); if (whspptr) { whspc = *whspptr; *whspptr = 0; } err += WriteOverview(conn, ANABase, group, xref, art, artLen, msgid); /* Repair string back to its former state */ if (whspptr) { *whspptr = whspc; } *ngroup = c; if (*ngroup == ',') ++ngroup; } while (ANABase) { ArtNumAss *an = ANABase; ANABase = an->an_Next; zfree(&conn->co_MemPool, an, sizeof(ArtNumAss)); } if (conn->co_Flags & COF_WASCONTROL) { if (DebugOpt) printf("Control message: %s %s\n", msgid, newsgroups); LogCmd(conn, 'c', control); if (DRIncomingLogPat != NULL) LogIncoming("%s c %s %s", conn->co_Auth.dr_Host, msgid, control); ExecuteControl(conn, control, art, artLen); } if (!err) { conn->co_Auth.dr_PostCount++; if (conn->co_Flags & COF_IHAVE) { MBLogPrintf(conn, &conn->co_TMBuf, "235\r\n"); } else { MBLogPrintf(conn, &conn->co_TMBuf, "239 %s\r\n", conn->co_IHaveMsgId); } } } zfreeStr(&conn->co_MemPool, &newsgroups); zfreeStr(&conn->co_MemPool, &msgid); zfreeStr(&conn->co_MemPool, &subject); zfreeStr(&conn->co_MemPool, &date); zfreeStr(&conn->co_MemPool, &xref); zfreeStr(&conn->co_MemPool, &control); zfreeStr(&conn->co_MemPool, &conn->co_IHaveMsgId); MBFree(&conn->co_ArtBuf); NNCommand(conn); }
int WriteOverview(Connection *conn, ArtNumAss *an, const char *group, const char *xref, const char *art, int artLen, const char *msgid) { artno_t artNo = 0; const char *body; char *xtmp = NULL; int xtmpLen = 16 + strlen(conn->co_Auth.dr_VServerDef->vs_ClusterName); char logbuf[1024]; int err = 0; /* * Locate article number assignment */ { ArtNumAss *scan; for (scan = an; scan; scan = scan->an_Next) { if (scan->an_GroupName == group) { artNo = scan->an_ArtNo; } xtmpLen += scan->an_GroupLen + 15; } } if (artNo == 0) return(0); /* * XXX We should find some way to aggregate these into one log entry. */ snprintf(logbuf, sizeof(logbuf), "%s %s:%lld", msgid, group, artNo); /* * Locate start of body (we may have to append our own Xref: line) */ { int l; int lnl = 1; for (l = 0; l < artLen; ++l) { /* * blank line terminates headers */ if (art[l] == '\r' && (l + 1 >= artLen || art[l+1] == '\n')) { if (lnl) break; } lnl = 0; if (art[l] == '\n') lnl = 1; } body = art + l; } /* * Write overview record. */ { off_t pos; OverInfo *ov; const OverArt *oa; hash_t hv = hhash(msgid); int actLen = 0; int iovLen = 0; int prealloc_ov, prealloc_oh; struct iovec iov[3]; if ((ov = GetOverInfo(group)) == NULL) { logit(LOG_ERR, "Error in GetOverInfo(%s) msgid=%s", group, msgid); LogCmd(conn, '-', logbuf); if (DRIncomingLogPat != NULL) LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf); MBLogPrintf(conn, &conn->co_TMBuf, "400 Error writing data\r\n"); NNTerminate(conn); return(1); } prealloc_ov = (ov->ov_MaxArts * sizeof(OverArt)) / 8; prealloc_oh = (1024 * ov->ov_Head->oh_DataEntries) / 8; if (MakeOverHFile(ov, artNo, 1) == NULL) { logit(LOG_ERR, "Error in MakeOverHFile() msgid=%s", msgid); LogCmd(conn, '-', logbuf); if (DRIncomingLogPat != NULL) LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf); MBLogPrintf(conn, &conn->co_TMBuf, "400 Error writing data\r\n"); NNTerminate(conn); return(1); } hflock(ov->ov_HCache->od_HFd, 0, XLOCK_EX); pos = lseek(ov->ov_HCache->od_HFd, 0L, 2); errno = 0; if (xref) { iov[0].iov_base = (void *)art; iov[0].iov_len = artLen + 1; iovLen = 1; } else { ArtNumAss *scan; int soff; xtmp = zalloc(&conn->co_MemPool, xtmpLen); sprintf(xtmp, "Xref: %s", DOpts.ReaderXRefHost); soff = strlen(xtmp); for (scan = an; scan; scan = scan->an_Next) { xtmp[soff++] = ' '; memcpy(xtmp + soff, scan->an_GroupName, scan->an_GroupLen); soff += scan->an_GroupLen; sprintf(xtmp + soff, ":%lld", scan->an_ArtNo); soff += strlen(xtmp + soff); } sprintf(xtmp + soff, "\r\n"); soff += 2; iov[0].iov_base = (void *)art; iov[0].iov_len = body - art; iov[1].iov_base = xtmp; iov[1].iov_len = soff; iov[2].iov_base = (void *)body; iov[2].iov_len = (art + artLen + 1) - body; iovLen = 3; } if (art[0] == 0) logit(LOG_ERR, "Warning: art[0] is NIL! %s", xtmp); { int i; for (i = 0; i < iovLen; ++i) actLen += iov[i].iov_len; } if (DOpts.ReaderXRefSlaveHost && (oa = GetOverArt(ov, artNo, NULL)) != NULL && oa->oa_MsgHash.h1 == hv.h1 && oa->oa_MsgHash.h2 == hv.h2 && OA_ARTNOEQ(artNo, oa->oa_ArtNo) ) { /* * We can detect duplicate articles in XRef slave mode. If * we see one, do not do anything. */ LogCmd(conn, 'd', logbuf); if (DRIncomingLogPat != NULL) LogIncoming("%s d %s%s", conn->co_Auth.dr_Host, "", logbuf); ; /* EMPTY */ } else if (DOpts.ReaderXOverMode == 0) { /* * Do not write xover info at all. This mode is not really * supported by the reader but may eventually be supported * in 100% nntp-cache mode if/when we develop it. */ logit(LOG_INFO, "ReaderXOverMode0 (%lld:%s)", artNo, msgid); LogCmd(conn, 'm', logbuf); if (DRIncomingLogPat != NULL) LogIncoming("%s m %s%s", conn->co_Auth.dr_Host, "", logbuf); ; /* EMPTY */ } else if ( DOpts.ReaderXOverMode == 2 || (FilePreAllocSpace(ov->ov_HCache->od_HFd, pos, prealloc_oh, iovLen) == 0 && writev(ov->ov_HCache->od_HFd, iov, iovLen) == actLen) ) { /* * Our write of the overview data succeeded or we were asked not * to write out the overview data. Write out the overview * article record. */ OverArt ovart = { 0 }; off_t ovpos = 0; hflock(ov->ov_OFd, 0, XLOCK_EX); (void)GetOverArt(ov, artNo, &ovpos); ovart.oa_ArtNo = OA_ARTNOSET(artNo); if (DOpts.ReaderXOverMode == 2) ovart.oa_SeekPos = -1; else ovart.oa_SeekPos = pos; ovart.oa_Bytes = actLen - 1; /* do not include \0 */ ovart.oa_MsgHash = hv; ovart.oa_TimeRcvd = (int)time(NULL); ovart.oa_ArtSize = (conn->co_ByteCounter > 0.0 ? conn->co_ByteCounter : conn->co_BytesHeader); lseek(ov->ov_OFd, ovpos, 0); FilePreAllocSpace(ov->ov_OFd, ovpos, prealloc_ov, sizeof(ovart)); write(ov->ov_OFd, &ovart, sizeof(ovart)); hflock(ov->ov_OFd, 0, XLOCK_UN); LogCmd(conn, '+', logbuf); if (DRIncomingLogPat != NULL) LogIncoming("%s + %s%s", conn->co_Auth.dr_Host, "", logbuf); } else { ftruncate(ov->ov_HCache->od_HFd, pos); logit(LOG_ERR, "error writing overview data file for %s", group); LogCmd(conn, '-', logbuf); if (DRIncomingLogPat != NULL) LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf); MBLogPrintf(conn, &conn->co_TMBuf, "400 Error writing data\r\n"); NNTerminate(conn); err = 1; } hflock(ov->ov_HCache->od_HFd, 0, XLOCK_UN); PutOverInfo(ov); } if (xtmp) zfree(&conn->co_MemPool, xtmp, xtmpLen); return(err); }
void AssignArticleNo(Connection *conn, ArtNumAss **pan, const char *group, const char *xref, int approved, const char *art, int artLen, const char *msgid) { const char *rec; int recLen; int groupLen = strlen(group); artno_t activeArtBeg; artno_t activeArtEnd; int aabegchanged = 0; int foundXRef = 0; int ts; char aabegbuf[20]; char aaendbuf[20]; artno_t artNo; char logbuf[1024]; if (DOpts.ReaderAutoAddToActive) { /* * locate group in active file and lock, create if it does not exist * You will have to manually add a GD, M, and fix S as appropriate * through some external process, if you use this. */ if ((rec = KPDBReadRecord(KDBActive, group, KP_LOCK, &recLen)) == NULL) { if (ValidGroupName(group) < 0) { /* logit(LOG_ERR, "group %s illegal", group); */ } else { char tsBuf[64]; KPDBWrite(KDBActive, group, "NB", "0000000001", KP_LOCK); KPDBWrite(KDBActive, group, "NE", "0000000000", KP_LOCK_CONTINUE); sprintf(tsBuf, "%08x", (int)time(NULL)); KPDBWrite(KDBActive, group, "CTS", tsBuf, KP_LOCK_CONTINUE); KPDBWrite(KDBActive, group, "LMTS", tsBuf, KP_LOCK_CONTINUE); KPDBWrite(KDBActive, group, "S", "y", KP_UNLOCK); } if ((rec = KPDBReadRecord(KDBActive, group, KP_LOCK, &recLen)) == NULL) { snprintf(logbuf, sizeof(logbuf), "%s %s not in dactive", msgid, group); LogCmd(conn, '-', logbuf); if (DRIncomingLogPat != NULL) LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf); return; } } } else { /* * locate group in active file and lock */ if ((rec = KPDBReadRecord(KDBActive, group, KP_LOCK, &recLen)) == NULL) { snprintf(logbuf, sizeof(logbuf), "%s %s not in dactive", msgid, group); LogCmd(conn, '-', logbuf); if (DRIncomingLogPat != NULL) LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf); return; } } /* * silently drop postings to moderated groups that do not have an * approved header. */ if (approved == 0) { int flagsLen; const char *flags = KPDBGetField(rec, recLen, "S", &flagsLen, "y"); while (flagsLen > 0) { if (*flags == 'm') { KPDBUnlock(KDBActive, rec); snprintf(logbuf, sizeof(logbuf), "%s %s unapproved", msgid, group); LogCmd(conn, '-', logbuf); if (DRIncomingLogPat != NULL) LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf); return; } --flagsLen; ++flags; } } /* * assign article number. Locate Xref: line if Xref's are enabled */ activeArtEnd = strtoll(KPDBGetField(rec, recLen, "NE", NULL, "-1"), NULL,10); activeArtBeg = strtoll(KPDBGetField(rec, recLen, "NB", NULL, "-1"), NULL,10); ts = (int)strtoul(KPDBGetField(rec, recLen, "LMTS", NULL, "0"), NULL, 16); artNo = activeArtEnd + 1; if (xref) { const char *test; for (test = strchr(xref, ' '); test; test = strchr(test, ' ')) { ++test; if (strncmp(test, group, groupLen) == 0 && test[groupLen] == ':') { artNo = strtoll(test + groupLen + 1, NULL, 10); foundXRef = 1; break; } } } /* * If we did not find an XRef entry and we are in xref-slave mode, * drop the newsgroup on the floor. */ if (foundXRef == 0 && DOpts.ReaderXRefSlaveHost != NULL) { KPDBUnlock(KDBActive, rec); snprintf(logbuf, sizeof(logbuf), "%s %s no valid xref present in slave mode", msgid, group); LogCmd(conn, '-', logbuf); if (DRIncomingLogPat != NULL) LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf); return; } if (artNo < 1) artNo = 1; if (activeArtEnd < artNo) { activeArtEnd = artNo; if (activeArtBeg > activeArtEnd) { activeArtBeg = activeArtEnd; aabegchanged = 1; } } else if (activeArtBeg > artNo) { activeArtBeg = artNo; aabegchanged = 1; if (activeArtEnd < activeArtBeg) activeArtEnd = activeArtBeg; } else if (activeArtBeg > activeArtEnd) { activeArtBeg = activeArtEnd = artNo; aabegchanged = 1; } { int nts = (int)time(NULL); if (nts != ts) { char tsBuf[64]; sprintf(tsBuf, "%08x", nts); KPDBWrite(KDBActive, group, "LMTS", tsBuf, KP_LOCK_CONTINUE); } } sprintf(aabegbuf, "%010lld", activeArtBeg); sprintf(aaendbuf, "%010lld", activeArtEnd); if (aabegchanged) KPDBWrite(KDBActive, group, "NB", aabegbuf, KP_LOCK_CONTINUE); /* continuing lock */ KPDBWrite(KDBActive, group, "NE", aaendbuf, KP_UNLOCK); /* and unlock */ { ArtNumAss *an = zalloc(&conn->co_MemPool, sizeof(ArtNumAss)); an->an_Next = *pan; *pan = an; an->an_GroupName = group; an->an_GroupLen = strlen(group); an->an_ArtNo = artNo; } }
void NNCommand2(Connection *conn) { char *ptr; char *cmd; char *buf; Command *scan; int len; conn->co_Func = NNCommand2; conn->co_State = "waitcmd"; /* * we have to be careful in regards to recursive operation, nor do * we want one descriptor to hog the process. We can't set RFds * because the next command may already be entirely loaded into an * MBuf so setting RFds may not unblock us. Instead, we set WFds * which basically forces a wakeup at some point in the future. */ if (conn->co_FCounter) { FD_SET(conn->co_Desc->d_Fd, &WFds); /* * if the other side closed the connection, select() is * not going to wake up for write(!) so set RFds too. */ if (conn->co_TMBuf.mh_WError) FD_SET(conn->co_Desc->d_Fd, &RFds); return; } ++conn->co_FCounter; /* * if there is still output pending, do not process the next * command. */ if (conn->co_TMBuf.mh_Bytes > 0 && !conn->co_TMBuf.mh_WError) return; /* * get command */ if ((len = MBReadLine(&conn->co_RMBuf, &buf)) == 0) { StatusUpdate(conn, "(idle)"); return; } conn->co_ByteCountType = DRBC_NONE; /* * check EOF */ if (len < 0 || conn->co_TMBuf.mh_WError) { NNTerminate(conn); return; } /* * strip CR LF */ ptr = buf; if (len > 1 && ptr[len-2] == '\r') ptr[len-2] = 0; if (DebugOpt) printf("command: %s\n", ptr); if (strncasecmp(ptr, "authinfo pass ", 14)) { LogCmd(conn, '<', ptr); } else { LogCmd(conn, '<', "authinfo pass **unlogged**"); } if (conn->co_Auth.dr_Flags & DF_USEPROXIED) { struct sockaddr_in sin; char *pt = NULL; if (strncasecmp(ptr, "proxied ", 8) || ! ((pt = strrchr(ptr, ':')))) { MBLogPrintf(conn, &conn->co_TMBuf, "400 %s: Proxy authentication failure.\r\n", conn->co_Auth.dr_VServerDef->vs_HostName ); NNTerminate(conn); } *pt++ = '\0'; ptr += 8; bzero((void *)&sin, sizeof(&sin)); sin.sin_family = AF_INET; sin.sin_port = htons(atoi(pt)); sin.sin_addr.s_addr = inet_addr(ptr); bcopy(&sin, &conn->co_Auth.dr_Addr, sizeof(conn->co_Auth.dr_Addr)); conn->co_Auth.dr_Flags &= ~DF_USEPROXIED; conn->co_Auth.dr_ResultFlags = DR_REQUIRE_DNS; return; } /* * extract command (note: StatusUpdate() will limit the line length) */ StatusUpdate(conn, "%s", ptr); if ((cmd = parseword(&ptr, " \t")) == NULL) { NNCommand(conn); return; } { int i; for (i = 0; cmd[i]; ++i) cmd[i] = tolower((int)(unsigned char)cmd[i]); } /* * Locate and execute command */ for (scan = &Cmds[0]; scan < &Cmds[arysize(Cmds)]; ++scan) { if (strcmp(cmd, scan->cmd_Name) == 0) { if (conn->co_Flags & COF_SERVER) { if (scan->cmd_Flags & CMDF_SERVER) { if ((conn->co_Auth.dr_Flags & DF_FEEDONLY) == 0) break; if ((scan->cmd_Flags & CMDF_NOTFEEDONLY) == 0) break; } } else { if (scan->cmd_Flags & CMDF_READER) break; } } } if (scan < &Cmds[arysize(Cmds)]) { if ((scan->cmd_Flags & CMDF_AUTH) && (conn->co_Auth.dr_Flags & DF_AUTHREQUIRED) ) { MBLogPrintf(conn, &conn->co_TMBuf, "480 Authentication required for command\r\n"); NNCommand(conn); } else { conn->co_ByteCountType = scan->cmd_DRBC_Type; scan->cmd_Func(conn, &ptr); } } else { NNUnknownCommand(conn); } }