void check_ref_counts(void) { struct floor flbuf; int a; int new_refcounts[MAXFLOORS]; syslog(LOG_DEBUG, "Checking floor reference counts\n"); for (a=0; a<MAXFLOORS; ++a) { new_refcounts[a] = 0; } cdb_begin_transaction(); CtdlForEachRoom(check_ref_counts_backend, (void *)new_refcounts ); cdb_end_transaction(); for (a=0; a<MAXFLOORS; ++a) { lgetfloor(&flbuf, a); flbuf.f_ref_count = new_refcounts[a]; if (new_refcounts[a] > 0) { flbuf.f_flags = flbuf.f_flags | QR_INUSE; } else { flbuf.f_flags = flbuf.f_flags & ~QR_INUSE; } lputfloor(&flbuf, a); syslog(LOG_DEBUG, "Floor %d: %d rooms\n", a, new_refcounts[a]); } }
/* * check_control - check the control record has sensible values for message, user and room numbers */ void check_control(void) { syslog(LOG_INFO, "Checking/re-building control record\n"); get_control(); // Find highest room number and message number. CtdlForEachRoom(control_find_highest, NULL); ForEachUser(control_find_user, NULL); put_control(); }
void cmd_lprm(char *argbuf) { int FloorBeingSearched = (-1); if (!IsEmptyStr(argbuf)) FloorBeingSearched = extract_int(argbuf, 0); cprintf("%d Public rooms:\n", LISTING_FOLLOWS); CtdlForEachRoom(cmd_lprm_backend, &FloorBeingSearched); cprintf("000\n"); }
// // Implements the LIST commands // void nntp_list(const char *cmd) { if (CtdlAccessCheck(ac_logged_in_or_guest)) return; char list_format[64]; char wildmat_pattern[1024]; struct nntp_list_data nld; extract_token(list_format, cmd, 1, ' ', sizeof list_format); extract_token(wildmat_pattern, cmd, 2, ' ', sizeof wildmat_pattern); if (strlen(wildmat_pattern) > 0) { nld.wildmat_pattern = wildmat_pattern; } else { nld.wildmat_pattern = NULL; } if ( (strlen(cmd) < 6) || (!strcasecmp(list_format, "ACTIVE")) ) { nld.list_format = NNTP_LIST_ACTIVE; } else if (!strcasecmp(list_format, "NEWSGROUPS")) { nld.list_format = NNTP_LIST_NEWSGROUPS; } else if (!strcasecmp(list_format, "OVERVIEW.FMT")) { nld.list_format = NNTP_LIST_OVERVIEW_FMT; } else { cprintf("501 syntax error , unsupported list format\r\n"); return; } // OVERVIEW.FMT delivers a completely different type of data than all of the // other LIST commands. It's a stupid place to put it. But that's how it's // written into RFC3977, so we have to handle it here. if (nld.list_format == NNTP_LIST_OVERVIEW_FMT) { cprintf("215 Order of fields in overview database.\r\n"); cprintf("Subject:\r\n"); cprintf("From:\r\n"); cprintf("Date:\r\n"); cprintf("Message-ID:\r\n"); cprintf("References:\r\n"); cprintf("Bytes:\r\n"); cprintf("Lines:\r\n"); cprintf(".\r\n"); return; } cprintf("215 list of newsgroups follows\r\n"); CtdlGetUser(&CC->user, CC->curr_user); CtdlForEachRoom(nntp_list_backend, &nld); cprintf(".\r\n"); }
void cmd_lrms(char *argbuf) { int FloorBeingSearched = (-1); if (!IsEmptyStr(argbuf)) FloorBeingSearched = extract_int(argbuf, 0); if (CtdlAccessCheck(ac_logged_in_or_guest)) return; CtdlGetUser(&CC->user, CC->curr_user); cprintf("%d Accessible rooms:\n", LISTING_FOLLOWS); CtdlForEachRoom(cmd_lrms_backend, &FloorBeingSearched); cprintf("000\n"); }
void PurgeMessages(void) { FILE *purgelist; syslog(LOG_DEBUG, "PurgeMessages() called"); messages_purged = 0; purgelist = tmpfile(); if (purgelist == NULL) { syslog(LOG_CRIT, "Can't create purgelist temp file: %s", strerror(errno)); return; } CtdlForEachRoom(GatherPurgeMessages, (void *)purgelist ); DoPurgeMessages(purgelist); fclose(purgelist); }
int PurgeRooms(void) { struct PurgeList *pptr; int num_rooms_purged = 0; struct ctdlroom qrbuf; struct ValidUser *vuptr; char *transcript = NULL; syslog(LOG_DEBUG, "PurgeRooms() called"); /* Load up a table full of valid user numbers so we can delete * user-owned rooms for users who no longer exist */ ForEachUser(AddValidUser, NULL); /* Then cycle through the room file */ CtdlForEachRoom(DoPurgeRooms, NULL); /* Free the valid user list */ while (ValidUserList != NULL) { vuptr = ValidUserList->next; free(ValidUserList); ValidUserList = vuptr; } transcript = malloc(SIZ); strcpy(transcript, "The following rooms have been auto-purged:\n"); while (RoomPurgeList != NULL) { if (CtdlGetRoom(&qrbuf, RoomPurgeList->name) == 0) { transcript=realloc(transcript, strlen(transcript)+SIZ); snprintf(&transcript[strlen(transcript)], SIZ, " %s\n", qrbuf.QRname); CtdlDeleteRoom(&qrbuf); } pptr = RoomPurgeList->next; free(RoomPurgeList); RoomPurgeList = pptr; ++num_rooms_purged; } if (num_rooms_purged > 0) CtdlAideMessage(transcript, "Room Autopurger Message"); free(transcript); syslog(LOG_DEBUG, "Purged %d rooms.", num_rooms_purged); return(num_rooms_purged); }
// // Implements the NEWGROUPS command // void nntp_newgroups(const char *cmd) { if (CtdlAccessCheck(ac_logged_in_or_guest)) return; char stringy_date[16]; char stringy_time[16]; char stringy_gmt[16]; struct tm tm; time_t thetime; extract_token(stringy_date, cmd, 1, ' ', sizeof stringy_date); extract_token(stringy_time, cmd, 2, ' ', sizeof stringy_time); extract_token(stringy_gmt, cmd, 3, ' ', sizeof stringy_gmt); memset(&tm, 0, sizeof tm); if (strlen(stringy_date) == 6) { sscanf(stringy_date, "%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday); tm.tm_year += 100; } else { sscanf(stringy_date, "%4d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday); tm.tm_year -= 1900; } tm.tm_mon -= 1; // tm_mon is zero based (0=January) tm.tm_isdst = (-1); // let the C library figure out whether DST is in effect sscanf(stringy_time, "%2d%2d%2d", &tm.tm_hour, &tm.tm_min ,&tm.tm_sec); thetime = mktime(&tm); if (!strcasecmp(stringy_gmt, "GMT")) { tzset(); thetime += timezone; } cprintf("231 list of new newsgroups follows\r\n"); CtdlGetUser(&CC->user, CC->curr_user); CtdlForEachRoom(nntp_newgroups_backend, &thetime); cprintf(".\r\n"); }
/* * Purge visits * * This is a really cumbersome "garbage collection" function. We have to * delete visits which refer to rooms and/or users which no longer exist. In * order to prevent endless traversals of the room and user files, we first * build linked lists of rooms and users which _do_ exist on the system, then * traverse the visit file, checking each record against those two lists and * purging the ones that do not have a match on _both_ lists. (Remember, if * either the room or user being referred to is no longer on the system, the * record is completely useless.) */ int PurgeVisits(void) { struct cdbdata *cdbvisit; visit vbuf; struct VPurgeList *VisitPurgeList = NULL; struct VPurgeList *vptr; int purged = 0; char IndexBuf[32]; int IndexLen; struct ValidRoom *vrptr; struct ValidUser *vuptr; int RoomIsValid, UserIsValid; /* First, load up a table full of valid room/gen combinations */ CtdlForEachRoom(AddValidRoom, NULL); /* Then load up a table full of valid user numbers */ ForEachUser(AddValidUser, NULL); /* Now traverse through the visits, purging irrelevant records... */ cdb_rewind(CDB_VISIT); while(cdbvisit = cdb_next_item(CDB_VISIT), cdbvisit != NULL) { memset(&vbuf, 0, sizeof(visit)); memcpy(&vbuf, cdbvisit->ptr, ( (cdbvisit->len > sizeof(visit)) ? sizeof(visit) : cdbvisit->len) ); cdb_free(cdbvisit); RoomIsValid = 0; UserIsValid = 0; /* Check to see if the room exists */ for (vrptr=ValidRoomList; vrptr!=NULL; vrptr=vrptr->next) { if ( (vrptr->vr_roomnum==vbuf.v_roomnum) && (vrptr->vr_roomgen==vbuf.v_roomgen)) RoomIsValid = 1; } /* Check to see if the user exists */ for (vuptr=ValidUserList; vuptr!=NULL; vuptr=vuptr->next) { if (vuptr->vu_usernum == vbuf.v_usernum) UserIsValid = 1; } /* Put the record on the purge list if it's dead */ if ((RoomIsValid==0) || (UserIsValid==0)) { vptr = (struct VPurgeList *) malloc(sizeof(struct VPurgeList)); vptr->next = VisitPurgeList; vptr->vp_roomnum = vbuf.v_roomnum; vptr->vp_roomgen = vbuf.v_roomgen; vptr->vp_usernum = vbuf.v_usernum; VisitPurgeList = vptr; } } /* Free the valid room/gen combination list */ while (ValidRoomList != NULL) { vrptr = ValidRoomList->next; free(ValidRoomList); ValidRoomList = vrptr; } /* Free the valid user list */ while (ValidUserList != NULL) { vuptr = ValidUserList->next; free(ValidUserList); ValidUserList = vuptr; } /* Now delete every visit on the purged list */ while (VisitPurgeList != NULL) { IndexLen = GenerateRelationshipIndex(IndexBuf, VisitPurgeList->vp_roomnum, VisitPurgeList->vp_roomgen, VisitPurgeList->vp_usernum); cdb_delete(CDB_VISIT, IndexBuf, IndexLen); vptr = VisitPurgeList->next; free(VisitPurgeList); VisitPurgeList = vptr; ++purged; } return(purged); }
/* * Begin the fulltext indexing process. */ void do_fulltext_indexing(void) { int i; static time_t last_index = 0L; static time_t last_progress = 0L; time_t run_time = 0L; time_t end_time = 0L; static int is_running = 0; if (is_running) return; /* Concurrency check - only one can run */ is_running = 1; /* * Don't do this if the site doesn't have it enabled. */ if (!CtdlGetConfigInt("c_enable_fulltext")) { return; } /* * Make sure we don't run the indexer too frequently. * FIXME move the setting into config */ if ( (time(NULL) - last_index) < 300L) { return; } /* * Check to see whether the fulltext index is up to date; if there * are no messages to index, don't waste any more time trying. */ if ( (CtdlGetConfigLong("MMfulltext") >= CtdlGetConfigLong("MMhighest")) && (CtdlGetConfigInt("MM_fulltext_wordbreaker") == FT_WORDBREAKER_ID) ) { return; /* nothing to do! */ } run_time = time(NULL); syslog(LOG_DEBUG, "do_fulltext_indexing() started (%ld)", run_time); /* * If we've switched wordbreaker modules, burn the index and start * over. */ begin_critical_section(S_CONTROL); if (CtdlGetConfigInt("MM_fulltext_wordbreaker") != FT_WORDBREAKER_ID) { syslog(LOG_DEBUG, "wb ver on disk = %d, code ver = %d", CtdlGetConfigInt("MM_fulltext_wordbreaker"), FT_WORDBREAKER_ID ); syslog(LOG_INFO, "(re)initializing full text index"); cdb_trunc(CDB_FULLTEXT); CtdlSetConfigLong("MMfulltext", 0); } end_critical_section(S_CONTROL); /* * Now go through each room and find messages to index. */ ft_newhighest = CtdlGetConfigLong("MMhighest"); CtdlForEachRoom(ft_index_room, NULL); /* load all msg pointers */ if (ft_num_msgs > 0) { qsort(ft_newmsgs, ft_num_msgs, sizeof(long), longcmp); for (i=0; i<(ft_num_msgs-1); ++i) { /* purge dups */ if (ft_newmsgs[i] == ft_newmsgs[i+1]) { memmove(&ft_newmsgs[i], &ft_newmsgs[i+1], ((ft_num_msgs - i - 1)*sizeof(long))); --ft_num_msgs; --i; } } /* Here it is ... do each message! */ for (i=0; i<ft_num_msgs; ++i) { if (time(NULL) != last_progress) { syslog(LOG_DEBUG, "Indexed %d of %d messages (%d%%)", i, ft_num_msgs, ((i*100) / ft_num_msgs) ); last_progress = time(NULL); } ft_index_message(ft_newmsgs[i], 1); /* Check to see if we need to quit early */ if (server_shutting_down) { syslog(LOG_DEBUG, "Indexer quitting early"); ft_newhighest = ft_newmsgs[i]; break; } /* Check to see if we have to maybe flush to disk */ if (i >= FT_MAX_CACHE) { syslog(LOG_DEBUG, "Time to flush."); ft_newhighest = ft_newmsgs[i]; break; } } free(ft_newmsgs); ft_num_msgs = 0; ft_num_alloc = 0; ft_newmsgs = NULL; } end_time = time(NULL); if (server_shutting_down) { is_running = 0; return; } syslog(LOG_DEBUG, "do_fulltext_indexing() duration (%ld)", end_time - run_time); /* Save our place so we don't have to do this again */ ft_flush_cache(); begin_critical_section(S_CONTROL); CtdlSetConfigLong("MMfulltext", ft_newhighest); CtdlSetConfigInt("MM_fulltext_wordbreaker", FT_WORDBREAKER_ID); end_critical_section(S_CONTROL); last_index = time(NULL); syslog(LOG_DEBUG, "do_fulltext_indexing() finished"); is_running = 0; return; }